/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *                                                                         *
 *  Merc Diku Mud improvments 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.                                               *
 *                                                                         *
 *  Dystopia Mud improvements copyright (C) 2000, 2001 by Brian Graversen  *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  *
 ***************************************************************************/

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>
#include "merc.h"

/*
===========================================================================
This snippet was written by Erwin S. Andreasen, erwin@pip.dknet.dk. You may 
use this code freely, as long as you retain my name in all of the files. You
also have to mail me telling that you are using it. I am giving this,
hopefully useful, piece of source code to you for free, and all I require
from you is some feedback.

Please mail me if you find any bugs or have any new ideas or just comments.

All my snippets are publically available at:

http://pip.dknet.dk/~pip1773/

If you do not have WWW access, try ftp'ing to pip.dknet.dk and examine
the /pub/pip1773 directory.

===========================================================================
*/

extern ROOM_INDEX_DATA *room_index_hash[MAX_KEY_HASH];
typedef enum
{ exit_from, exit_to, exit_both }
exit_status;
const sh_int opposite_dir[6] = { DIR_SOUTH, DIR_WEST, DIR_NORTH, DIR_EAST, DIR_DOWN, DIR_UP };

/*
 * get the 'short' name of an area (e.g. MIDGAARD, MIRROR etc.
 * assumes that the filename saved in the AREA_DATA struct is something like midgaard.are
 */
char *area_name(AREA_DATA * pArea)
{
  static char buffer[64];
  char *period;

  assert(pArea != NULL);

  strncpy(buffer, pArea->filename, 64);
  period = strchr(buffer, '.');
  if (period)
    *period = '\0';
  return buffer;
}

void room_pair(ROOM_INDEX_DATA * left, ROOM_INDEX_DATA * right, exit_status ex, char *buffer)
{
  char *sExit;

  switch (ex)
  {
    default:
      sExit = "??";
      break;                    /* invalid usage */
    case exit_from:
      sExit = "< ";
      break;
    case exit_to:
      sExit = " >";
      break;
    case exit_both:
      sExit = "<>";
      break;
  }
  sprintf(buffer, "%5d %-26.26s %s%5d %-26.26s(%-8.8s)\n\r", left->vnum, left->name, sExit, right->vnum, right->name, area_name(right->area));
  return;
}

/* for every exit in 'room' which leads to or from pArea but NOT both, print it */
void checkexits(ROOM_INDEX_DATA * room, AREA_DATA * pArea, char *buffer)
{
  char buf[MAX_STRING_LENGTH];
  int i;
  EXIT_DATA *exit;
  ROOM_INDEX_DATA *to_room;

  strcpy(buffer, "");

  for (i = 0; i < 6; i++)
  {
    exit = room->exit[i];
    if (!exit)
      continue;
    else
      to_room = exit->to_room;
    if (to_room)
    {
      if ((room->area == pArea) && (to_room->area != pArea))
      {
        if (to_room->exit[opposite_dir[i]] && to_room->exit[opposite_dir[i]]->to_room == room)
          room_pair(room, to_room, exit_both, buf); /* <> */
        else
          room_pair(room, to_room, exit_to, buf); /* > */
        strcat(buffer, buf);
      }
      else
      {
        if ((room->area != pArea) && (exit->to_room->area == pArea))
        {                       /* an exit from another area to our area */
          if (!(to_room->exit[opposite_dir[i]] && to_room->exit[opposite_dir[i]]->to_room == room))
          {                     /* two-way exits are handled in the other if */
            room_pair(to_room, room, exit_from, buf);
            strcat(buffer, buf);
          }
        }                       /* if room->area */
      }                         /* for */
    }
  }
  return;
}

/* for now, no arguments, just list the current area */
void do_exlist(CHAR_DATA * ch, char *argument)
{
  AREA_DATA *pArea;
  ROOM_INDEX_DATA *room;
  int i;
  char buffer[MAX_STRING_LENGTH];
  bool found = FALSE;

  pArea = ch->in_room->area;
  for (i = 0; i < MAX_KEY_HASH; i++)
  {
    for (room = room_index_hash[i]; room != NULL; room = room->next)
    {
      checkexits(room, pArea, buffer);
      if (buffer[0] != '\0') found = TRUE;
      send_to_char(buffer, ch);
    }
  }
  if (!found) send_to_char("No exists found.\n\r", ch);
}

void do_reimb(CHAR_DATA * ch, char *argument)
{
  CHAR_DATA *vch;
  char arg[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  int v;

  argument = one_argument(argument, arg);
  if (arg[0] == '\0')
  {
    send_to_char("Reimburse <target> <xp|qp> <amount>\n\r", ch);
    return;
  }
  if ((vch = get_char_world(ch, arg)) == NULL)
  {
    send_to_char("They aren't logged on.\n\r", ch);
    return;
  }
  if (IS_NPC(vch))
  {
    send_to_char("That is a mob.\n\r", ch);
    return;
  }
  argument = one_argument(argument, arg);
  argument = one_argument(argument, arg2);
  v = atoi(arg2);
  if (arg[0] == '\0' || arg2[0] == '\0' || (!is_number(arg2) && v >= 0))
  {
    do_reimb(ch, "");
    return;
  }
  if (!str_cmp(arg, "xp"))
  {
    vch->exp += v;
    vch->pcdata->score[SCORE_TOTAL_XP] += v;
  }
  else if (!str_cmp(arg, "qp"))
  {
    vch->pcdata->quest += v;
    vch->pcdata->questtotal += v;
  }
  else
  {
    send_to_char("Please specify XP or QP.\n\r", ch);
    return;
  }
  if (vch->mkill < 5)
  {
    vch->mkill = 5;
    do_autosave(ch, "");
  }
  sprintf(arg2, "%s reimbursed %d %s.\n\r", vch->name, v, arg);
  send_to_char(arg2, ch);
  sprintf(arg2, "%s has reimbursed you %d %s.\n\r", ch->name, v, arg);
  send_to_char(arg2, vch);
}

void do_affects(CHAR_DATA * ch, char *argument)
{
  char buf[MAX_STRING_LENGTH];
  AFFECT_DATA *paf;

  if (IS_NPC(ch))
    return;

  if (IS_ITEMAFF(ch, ITEMA_CHAOSSHIELD))
    send_to_char("#pChaosshield#n.\n\r", ch);
  if (IS_AFFECTED(ch, AFF_SANCTUARY))
    send_to_char("#9Sanctuary#n.\n\r", ch);
  if (IS_AFFECTED(ch, AFF_PROTECT))
    send_to_char("#LProtection from evil#n.\n\r", ch);
  if (IS_AFFECTED(ch, AFF_PROTECT_GOOD))
    send_to_char("#LProtection from good#n.\n\r", ch);
  if (IS_AFFECTED(ch, AFF_FLYING))
    send_to_char("#cFly#n\n\r", ch);
  send_to_char("\n\r", ch);
  if (ch->affected == NULL)
  {
    send_to_char("You have nothing affecting you at this time.\n\r", ch);
    return;
  }
  if (ch->affected != NULL)
  {

    send_to_char("You are affected by:\n\r", ch);
    for (paf = ch->affected; paf != NULL; paf = paf->next)
    {
      sprintf(buf, "Spell: '%s'", skill_table[paf->type].name);
      send_to_char(buf, ch);
      if (ch->level >= 0)
      {
        sprintf(buf, " modifies %s by %d for %d hours with bits %s.\n\r", affect_loc_name(paf->location), paf->modifier, paf->duration, affect_bit_name(paf->bitvector));
        send_to_char(buf, ch);
      }

    }

  }

  return;

}

char *plr_bit_name(int arg)
{
  static char buf[512];

  buf[0] = '\0';

  if (arg & PLR_IS_NPC)
    strcat(buf, " npc");
  if (arg & PLR_AUTOEXIT)
    strcat(buf, " autoexit");
  if (arg & PLR_AUTOLOOT)
    strcat(buf, " autoloot");
  if (arg & PLR_AUTOSAC)
    strcat(buf, " autosac");
  if (arg & PLR_BRIEF1)
    strcat(buf, " brief");
  if (arg & PLR_PROMPT)
    strcat(buf, " prompt");
  if (arg & PLR_TELNET_GA)
    strcat(buf, " telnet_ga");
  if (arg & PLR_HOLYLIGHT)
    strcat(buf, " holylight");
  if (arg & PLR_WIZINVIS)
    strcat(buf, " wizinvis");
  if (arg & PLR_ANSI)
    strcat(buf, " ansi");
  if (arg & PLR_SILENCE)
    strcat(buf, " silenced");
  if (arg & PLR_LOG)
    strcat(buf, " log");
  if (arg & PLR_FREEZE)
    strcat(buf, " freeze");
  return (buf[0] != '\0') ? buf + 1 : "none";
}

char *extra_plr_bit_name(int arg)
{
  static char buf[512];

  buf[0] = '\0';

  if (arg & EXTRA_NEWPASS)
    strcat(buf, " newpass");
  if (arg & EXTRA_OSWITCH)
    strcat(buf, " oswitch");
  if (arg & TIED_UP)
    strcat(buf, " tied_up");
  if (arg & GAGGED)
    strcat(buf, " gagged");
  if (arg & BLINDFOLDED)
    strcat(buf, " blindfolded");
  if (arg & EXTRA_DONE)
    strcat(buf, " non_virgin");
  if (arg & EXTRA_EXP)
    strcat(buf, " got_exp");
  if (arg & EXTRA_PREGNANT)
    strcat(buf, " pregnant");
  if (arg & EXTRA_LABOUR)
    strcat(buf, " labour");
  if (arg & EXTRA_BORN)
    strcat(buf, " born");
  if (arg & EXTRA_PROMPT)
    strcat(buf, " prompt");
  if (arg & EXTRA_MARRIED)
    strcat(buf, " married");
  if (arg & EXTRA_CALL_ALL)
    strcat(buf, " call_all");
  return (buf[0] != '\0') ? buf + 1 : "none";
}
char *get_position_name(int arg)
{
  switch (arg)
  {
    case 0:
      return "dead";
    case 1:
      return "mortal";
    case 2:
      return "incap";
    case 3:
      return "stunned";
    case 4:
      return "sleeping";
    case 5:
      return "meditating";
    case 6:
      return "sitting";
    case 7:
      return "resting";
    case 8:
      return "fighting";
    case 9:
      return "standing";
  }
  bug("Get_position_name: unknown type %d.", arg);
  return "(unknown)";
}

/*
 * Itemaffect bit names :)
 */
char *itemaffect_bit_name(int arg)
{
  static char buf[512];

  buf[0] = '\0';

  if (arg & ITEMA_CHAOSSHIELD)
    strcat(buf, " Chaoshield");
  if (arg & ITEMA_ARTIFACT)
    strcat(buf, " Artifact");
  if (arg & ITEMA_REGENERATE)
    strcat(buf, " Regeneration");
  if (arg & ITEMA_SPEED)
    strcat(buf, " Speed");
  if (arg & ITEMA_VORPAL)
    strcat(buf, " Vorpal");
  if (arg & ITEMA_RESISTANCE)
    strcat(buf, " Resistance");
  if (arg & ITEMA_VISION)
    strcat(buf, " Vision");
  if (arg & ITEMA_STALKER)
    strcat(buf, " Stalker");
  if (arg & ITEMA_VANISH)
    strcat(buf, " Vanish");
  return (buf[0] != '\0') ? buf + 1 : "none";
}

/*
 * Pstat code by Tijer
 */
void do_pstat(CHAR_DATA * ch, char *argument)
{
  char arg[MAX_INPUT_LENGTH];
  char buf[MAX_STRING_LENGTH];
  CHAR_DATA *victim;

  argument = one_argument(argument, arg);

  if (arg[0] == '\0')
  {
    send_to_char("Pstat whom?\n\r", ch);
    return;
  }

  if ((victim = get_char_world(ch, arg)) == NULL)
  {
    send_to_char("They aren't here.\n\r", ch);
    return;
  }

  sprintf(buf, "Name : %s.\n\r", IS_NPC(victim) ? victim->short_descr : victim->name);
  send_to_char(buf, ch);
  sprintf(buf, "Sex : %s. Room : %d. Align : %d. Primal : %d. Quest : %d.\n\r",
          victim->sex == SEX_MALE ? "Male" :
          victim->sex == SEX_FEMALE ? "Female" : "None", victim->in_room == NULL ? 0 : victim->in_room->vnum, victim->alignment, victim->practice, IS_NPC(victim) ? 0 : victim->pcdata->quest);
  send_to_char(buf, ch);

  sprintf(buf, "Level : %d. Trust : %d. Exp : %d.", victim->level, victim->trust, victim->exp);
  send_to_char(buf, ch);

  if (!IS_NPC(victim))
  {
    sprintf(buf, " PlayerID : %d.\n\r", victim->pcdata->playerid);
    send_to_char(buf, ch);
  }
  else
    send_to_char("\n\r", ch);

  sprintf(buf, "Hit : %d. Dam : %d. AC : %d. Position : %s\n\r", char_hitroll(victim), char_damroll(victim), char_ac(victim), capitalize(get_position_name(victim->position)));
  send_to_char(buf, ch);

  sprintf(buf, "HP %d/%d. Mana %d/%d. Move %d/%d.\n\r", victim->hit, victim->max_hit, victim->mana, victim->max_mana, victim->move, victim->max_move);
  send_to_char(buf, ch);

  sprintf(buf, "Str: %d.  Int: %d.  Wis: %d.  Dex: %d.  Con: %d.\n\r", get_curr_str(victim), get_curr_int(victim), get_curr_wis(victim), get_curr_dex(victim), get_curr_con(victim));
  send_to_char(buf, ch);

  sprintf(buf, "Fighting : %s. (%d)\n\r", victim->fighting ? victim->fighting->name : "(None)", victim->fighting ? victim->fighting->level : 0);
  send_to_char(buf, ch);

  sprintf(buf, "Pkill : %d. Pdeath : %d. Mkill : %d. Mdeath : %d.\n\r",
          IS_NPC(victim) ? 0 : victim->pkill, IS_NPC(victim) ? 0 : victim->pdeath, IS_NPC(victim) ? 0 : victim->mkill, IS_NPC(victim) ? 0 : victim->mdeath);
  send_to_char(buf, ch);

  sprintf(buf, "TotExp  : %12d. TotMobLev  : %10d. TotQuestPoints : %10d.\n\r",
          IS_NPC(victim) ? 0 : victim->pcdata->score[SCORE_TOTAL_XP], IS_NPC(victim) ? 0 : victim->pcdata->score[SCORE_TOTAL_LEVEL], IS_NPC(victim) ? 0 : victim->pcdata->score[SCORE_QUEST]);
  send_to_char(buf, ch);

  sprintf(buf, "HighExp : %12d. HighMobLev : %10d. Tot#Quests     : %10d.\n\r",
          IS_NPC(victim) ? 0 : victim->pcdata->score[SCORE_HIGH_XP], IS_NPC(victim) ? 0 : victim->pcdata->score[SCORE_HIGH_LEVEL], IS_NPC(victim) ? 0 : victim->pcdata->score[SCORE_NUM_QUEST]);
  send_to_char(buf, ch);

  if (!IS_NPC(victim))
  {
    sprintf(buf, "Unarmed : %4d.", victim->wpn[0]);
    send_to_char(buf, ch);
    sprintf(buf, " Slice   : %4d.", victim->wpn[1]);
    send_to_char(buf, ch);
    sprintf(buf, " Stab    : %4d.", victim->wpn[2]);
    send_to_char(buf, ch);
    sprintf(buf, " Slash   : %4d.", victim->wpn[3]);
    send_to_char(buf, ch);
    sprintf(buf, " Whip    : %4d.\n\r", victim->wpn[4]);
    send_to_char(buf, ch);
    sprintf(buf, "Claw    : %4d.", victim->wpn[5]);
    send_to_char(buf, ch);
    sprintf(buf, " Blast   : %4d.", victim->wpn[6]);
    send_to_char(buf, ch);
    sprintf(buf, " Pound   : %4d.", victim->wpn[7]);
    send_to_char(buf, ch);
    sprintf(buf, " Crush   : %4d.", victim->wpn[8]);
    send_to_char(buf, ch);
    sprintf(buf, " Grep    : %4d.\n\r", victim->wpn[9]);
    send_to_char(buf, ch);
    sprintf(buf, "Bite    : %4d.", victim->wpn[10]);
    send_to_char(buf, ch);
    sprintf(buf, " Pierce  : %4d.", victim->wpn[11]);
    send_to_char(buf, ch);
    sprintf(buf, " Suck    : %4d.\n\r", victim->wpn[12]);
    send_to_char(buf, ch);

    sprintf(buf, "%-8s : %3d. %-8s : %3d. %-8s : %3d. %-8s : %3d. %-8s : %3d.\n\r",
            "Purple", victim->spl[PURPLE_MAGIC], "Red", victim->spl[RED_MAGIC], "Blue", victim->spl[BLUE_MAGIC], "Green", victim->spl[GREEN_MAGIC], "Yellow", victim->spl[YELLOW_MAGIC]);
    send_to_char(buf, ch);
    sprintf(buf, "%-8s : %3d. %-8s : %3d. %-8s : %3d. %-8s : %3d. %-8s : %3d.\n\r",
            "Viper", victim->stance[STANCE_VIPER],
            "Crane", victim->stance[STANCE_CRANE], "Crab", victim->stance[STANCE_CRAB], "Mongoose", victim->stance[STANCE_MONGOOSE], "Bull", victim->stance[STANCE_BULL]);
    send_to_char(buf, ch);

    sprintf(buf, "%-8s : %3d. %-8s : %3d. %-8s : %3d. %-8s : %3d. %-8s : %3d.\n\r",
            "Mantis", victim->stance[STANCE_MANTIS],
            "Dragon", victim->stance[STANCE_DRAGON], "Tiger", victim->stance[STANCE_TIGER], "Monkey", victim->stance[STANCE_MONKEY], "Swallow", victim->stance[STANCE_SWALLOW]);

    send_to_char(buf, ch);
    sprintf(buf, "%-8s : %3d. %-8s : %3d. %-8s : %3d. %-8s : %3d. %-8s : %3d.\n\r",
            "ss1", victim->stance[STANCE_SS1], "ss2", victim->stance[STANCE_SS2], "ss3", victim->stance[STANCE_SS3], "ss4", victim->stance[STANCE_SS4], "ss5", victim->stance[STANCE_SS5]);
    send_to_char(buf, ch);

    sprintf(buf, "Act         : %s\n\r", plr_bit_name(victim->act));
    send_to_char(buf, ch);
    sprintf(buf, "Extra       : %s\n\r", victim->extra <= 0 ? "(None)" : extra_plr_bit_name(victim->extra));
    send_to_char(buf, ch);
    sprintf(buf, "ItemAff     : %s\n\r", victim->itemaffect <= 0 ? "(None)" : itemaffect_bit_name(victim->itemaffect));
    send_to_char(buf, ch);

    sprintf(buf, "Affected by : %s.\n\r", affect_bit_name(victim->affected_by));
    send_to_char(buf, ch);

    return;
  }
}

/* agrr_test by blade of E, version 1.31. */
void aggr_test(CHAR_DATA * ch)
{
  char buf[60];
  CHAR_DATA *wch;
  CHAR_DATA *wch_next;
  CHAR_DATA *victim;

  if (!IS_NPC(ch) && ch->level < 7 && ch->in_room != NULL && !IS_SET(ch->in_room->room_flags, ROOM_SAFE))
  {
    for (wch = ch->in_room->people; wch != NULL; wch = wch_next)
    {
      wch_next = wch->next_in_room;
      if (!IS_NPC(wch) || !IS_SET(wch->act, ACT_AGGRESSIVE)
          || wch->fighting != NULL || IS_AFFECTED(wch, AFF_CHARM) || !IS_AWAKE(wch) || (IS_SET(wch->act, ACT_WIMPY) && IS_AWAKE(ch)) || !can_see(wch, ch) || number_bits(2) == 0)
      {
        continue;
      }
      victim = wch;
      if (victim == NULL)
        continue;
      sprintf(buf, "%s screams and attacks!\n\r", victim->name);
      send_to_char(buf, ch);
      multi_hit(victim, ch, TYPE_UNDEFINED);
    }
  }
  return;
}