6D/
6D/area/
6D/boards/
6D/city/
6D/color/
6D/corpses/
6D/councils/
6D/htowns/
6D/news/
6D/specials/
6D/src/specials/
6D/src/trades/
#include "h/mud.h"
#include <string.h>
#include <ctype.h>
#include <time.h>
#include "h/files.h"
#include "h/currency.h"

void                    free_bank_to_chars(BANK_DATA * bank);

CHAR_DATA              *find_banker(CHAR_DATA *ch)
{
  CHAR_DATA              *banker = NULL;

  for(banker = ch->in_room->first_person; banker; banker = banker->next_in_room)
    if(IS_NPC(banker) && xIS_SET(banker->act, ACT_BANKER))
      break;

  return banker;
}

/* Quick function for immortals/staff to list all bankers in the world */
void do_bankers(CHAR_DATA *ch, char *argument)
{

  CHAR_DATA              *mob;

  for(mob = first_char; mob; mob = mob->next)
  {
    if(IS_NPC(mob))
    {
      if(xIS_SET(mob->pIndexData->act, ACT_BANKER))
        ch_printf(ch, "&R[%d] Banker '%s', level %d : in room [%d] - %s..\n\r", mob->pIndexData->vnum, mob->short_descr, mob->level, mob->in_room->vnum, mob->in_room->area->name);
      else if(xIS_SET(mob->act, ACT_BANKER))
        ch_printf(ch, "&W[%d] Banker '%s', level %d : in room [%d] - %s..\n\r", mob->pIndexData->vnum, mob->short_descr, mob->level, mob->in_room->vnum, mob->in_room->area->name);
    }
  }

  send_to_char("&wMobs in &Wwhite &ware current, &Rred &ware proto.\n\r", ch);
  return;
}

void unlink_bank(BANK_DATA * bank)
{
  BANK_DATA              *tmp, *tmp_next;
  int                     hash;

  if(!bank)
  {
    bug("Unlink_bank: NULL bank");
    return;
  }

  if(bank->name[0] < 'a' || bank->name[0] > 'z')
    hash = 0;
  else
    hash = (bank->name[0] - 'a') + 1;

  if(bank == (tmp = bank_index[hash]))
  {
    bank_index[hash] = tmp->next;
    return;
  }
  for(; tmp; tmp = tmp_next)
  {
    tmp_next = tmp->next;
    if(bank == tmp_next)
    {
      tmp->next = tmp_next->next;
      return;
    }
  }
}

void free_bank(BANK_DATA * bank)
{
  if(bank->name)
    STRFREE(bank->name);
  if(bank->password)
    STRFREE(bank->password);
  DISPOSE(bank);
}

void free_banks(void)
{
  BANK_DATA              *bank, *bank_next;
  int                     hash;

  for(hash = 0; hash < 126; hash++)
  {
    for(bank = bank_index[hash]; bank; bank = bank_next)
    {
      bank_next = bank->next;
      unlink_bank(bank);
      free_bank(bank);
    }
  }
}

void add_bank(BANK_DATA * bank)
{
  int                     hash, x;
  BANK_DATA              *tmp, *prev;

  if(!bank)
  {
    bug("Add_bank: NULL bank");
    return;
  }

  if(!bank->name)
  {
    bug("Add_bank: NULL bank->name");
    return;
  }

  if(!bank->password)
  {
    bug("Add_bank: NULL bank->password");
    return;
  }

  for(x = 0; bank->name[x] != '\0'; x++)
    bank->name[x] = LOWER(bank->name[x]);
  if(bank->name[0] < 'a' || bank->name[0] > 'z')
    hash = 0;
  else
    hash = (bank->name[0] - 'a') + 1;

  if((prev = tmp = bank_index[hash]) == NULL)
  {
    bank->next = bank_index[hash];
    bank_index[hash] = bank;
    return;
  }

  for(; tmp; tmp = tmp->next)
  {
    if((x = strcmp(bank->name, tmp->name)) == 0)
    {
      bug("Add_bank: trying to add duplicate name to bucket %d", hash);
      free_bank(bank);
      return;
    }
    else if(x < 0)
    {
      if(tmp == bank_index[hash])
      {
        bank->next = bank_index[hash];
        bank_index[hash] = bank;
        return;
      }
      prev->next = bank;
      bank->next = tmp;
      return;
    }
    prev = tmp;
  }
  /*
   * add to end
   */
  prev->next = bank;
  bank->next = NULL;
  return;
}

// Volk Jan-16: Quick command to merge two accounts
void do_merge(CHAR_DATA *ch, char *argument)
{
  BANK_DATA              *bank, *bank2;
  CHAR_DATA              *banker;
  char                    arg1[MIL], arg2[MIL], arg3[MIL], arg4[MIL];
  char                    buf[MSL];

  if(!(banker = find_banker(ch)))
  {
    send_to_char("You're not in a bank!\r\n", ch);
    return;
  }

  if(IS_NPC(ch))
  {
    snprintf(buf, MSL, "say Sorry, %s, we don't do business with mobs.", ch->name);
    interpret(banker, buf);
    return;
  }

  if(argument[0] == '\0')
  {
    send_to_char("Syntax: merge (name) (password) (name2) (password2)\r\n", ch);
    send_to_char("        using the name and password of the first account, then the second.\r\n", ch);
    send_to_char("The first account will be kept, with the funds from both accounts. The second will be deleted.\r\n", ch);
    interpret(banker, (char *)"say If you need help type &WHELP BANK&D.");
    return;
  }

  argument = one_argument(argument, arg1);
  argument = one_argument(argument, arg2);
  argument = one_argument(argument, arg3);
  argument = one_argument(argument, arg4);

  bank = find_bank(arg1);
  bank2 = find_bank(arg3);

  if(!bank)
  {
    ch_printf(ch, "There is no account by the name of '%s'.\r\n", arg1);
    return;
  }

  if(!bank2)
  {
    ch_printf(ch, "There is no account by the name of '%s'.\r\n", arg3);
    return;
  }

  if(strcmp(sha256_crypt(arg2), bank->password))
  {
    ch_printf(ch, "Invalid password for account '%s'.\r\n", arg1);
    return;
  }

  if(strcmp(sha256_crypt(arg4), bank2->password))
  {
    ch_printf(ch, "Invalid password for account '%s'.\r\n", arg3);
    return;
  }

  ch_printf(ch, "Moving %d gold to account '%s' (previously had %d gold).\r\n", bank2->gold, arg1, bank->gold);
  bank->gold += bank2->gold;
  bank2->gold = 0;
  ch_printf(ch, "Moving %d silver to account '%s' (previously had %d silver).\r\n", bank2->silver, arg1, bank->silver);
  bank->silver += bank2->silver;
  bank2->silver = 0;
  ch_printf(ch, "Moving %d bronze to account '%s' (previously had %d bronze).\r\n", bank2->bronze, arg1, bank->bronze);
  bank->bronze += bank2->bronze;
  bank2->bronze = 0;
  ch_printf(ch, "Moving %d copper to account '%s' (previously had %d copper).\r\n", bank2->copper, arg1, bank->copper);
  bank->copper += bank2->copper;
  bank2->copper = 0;
  bank->lastused = current_time;

  ch_printf(ch, "Deleting... (%s)\r\n", bank2->name);
  free_bank_to_chars(bank2);
  unlink_bank(bank2);
  free_bank(bank2);
  save_bank();

  if(ch->pcdata && ch->pcdata->account)
    STRFREE(ch->pcdata->account);

  ch_printf(ch, "Account '%s' has successfully been deleted.\r\n", arg3);
  send_to_char("Please reselect your active account using the 'ACCOUNT' command.\r\n", ch);

  return;
}

void do_account(CHAR_DATA *ch, char *argument)
{
  BANK_DATA              *bank;
  CHAR_DATA              *banker;
  char                    arg1[MIL], arg2[MIL], arg3[MIL];
  int                     amount = 0, currtime = time(0);
  int                     type = DEFAULT_CURR;
  char                    buf[MSL], *pwdnew;

  if(!(banker = find_banker(ch)))
  {
    send_to_char("You're not in a bank!\r\n", ch);
    return;
  }

  if(IS_NPC(ch))
  {
    snprintf(buf, MSL, "say Sorry, %s, we don't do business with mobs.", ch->name);
    interpret(banker, buf);
    return;
  }

  if(argument[0] == '\0')
  {
    send_to_char("Syntax: account name password create/delete\r\n", ch);
    send_to_char("        account name password - to switch accounts\r\n", ch);
    interpret(banker, (char *)"say If you need help type &WHELP BANK&D.");
    return;
  }

  argument = one_argument(argument, arg1);
  argument = one_argument(argument, arg2);
  argument = one_argument(argument, arg3);

  bank = find_bank(arg1); // account saved to pfile

  if(str_cmp(arg3, "create") && str_cmp(arg3, "delete"))
  {
    // add check here for correct password 
    if(!bank)
    {
      interpret(banker, (char *)"say There is no account with that name. Please use the correct name, or create a new account.");
      send_to_char("&wTo learn more, type &WHELP BANK&w.\r\n", ch);
      return;
    }
    if(strcmp(sha256_crypt(arg2), bank->password))
    {
      send_to_char("Invalid password.\r\n", ch);
      return;
    }

    if(ch->pcdata->account)
    {
      if(str_cmp(ch->pcdata->account, arg1))
      {
        ch_printf(ch, "You switch bank account from '%s' to '%s'.\r\n", ch->pcdata->account, arg1);
        STRFREE(ch->pcdata->account);
        ch->pcdata->account = STRALLOC(arg1);
      }
      else
        ch_printf(ch, "Account '%s' is already selected.\r\n", arg1);
    }
    else
    {
      ch_printf(ch, "Account '%s' has been selected.\r\n", arg1);
      ch->pcdata->account = STRALLOC(arg1);
    }
    return;
  }

  if(!str_cmp(arg3, "create") && (arg2))
  {

    if(strlen(arg1) < 4)
    {
      send_to_char("Account name must be at least 4 characters.\r\n", ch);
      return;
    }

    if(strlen(arg2) < 5)
    {
      send_to_char("Invalid Password.  Must be at least 5 characters in length.\r\n", ch);
      return;
    }
    if(arg2[0] == '!')
    {
      send_to_char("Password cannot begin with the '!' character.\r\n", ch);
      return;
    }

    if(bank)
    {
      send_to_char("There is already an account with that name!\r\n", ch);
      return;
    }

    if((currtime - ch->pcdata->lastaccountcreated) < 3600 && get_trust(ch) < LEVEL_AJ_LT)
    {
      send_to_char("Please wait at least one hour from previous creation time to make a new account.\r\n", ch);
      return;
    }

    pwdnew = sha256_crypt(arg2);
    CREATE(bank, BANK_DATA, 1);
    bank->lastused = current_time;
    bank->name = STRALLOC(arg1);
    bank->password = STRALLOC(pwdnew);
    bank->bronze = 0;
    bank->copper = 0;
    bank->gold = 0;
    bank->silver = 0;
    add_bank(bank);
    save_bank();
    ch->pcdata->lastaccountcreated = currtime;
    if(ch->pcdata->account)
      STRFREE(ch->pcdata->account);
    ch->pcdata->account = STRALLOC(arg1);
    save_char_obj(ch);
    saving_char = NULL;
    send_to_char("Your account has been added.\r\n", ch);
    return;
  }

  if(!str_cmp(arg3, "delete") && (arg2))
  {
    if(!bank)
    {
      send_to_char("There is no account with that name to delete!\r\n", ch);
      return;
    }
    if(strcmp(sha256_crypt(arg2), bank->password))
    {
      send_to_char("Invalid password.\r\n", ch);
      return;
    }

    GET_MONEY(ch, CURR_GOLD) += bank->gold;
    GET_MONEY(ch, CURR_SILVER) += bank->silver;
    GET_MONEY(ch, CURR_BRONZE) += bank->bronze;
    GET_MONEY(ch, CURR_COPPER) += bank->copper;
    ch_printf(ch, "Deleting... (%s)\r\n", bank->name);
    free_bank_to_chars(bank);
    unlink_bank(bank);
    free_bank(bank);
    save_bank();
    ch->pcdata->lastaccountcreated = 0;
    if(ch->pcdata->account)
      STRFREE(ch->pcdata->account);
    save_char_obj(ch);
    saving_char = NULL;
    send_to_char("Your account has successfully been deleted.\r\n", ch);
    return;
  }

}

void do_deposit(CHAR_DATA *ch, char *argument)
{
  BANK_DATA              *bank;
  CHAR_DATA              *banker;
  char                    arg1[MIL];
  char                    arg2[MIL];
  int                     amount = 0, currtime = time(0);
  int                     type = DEFAULT_CURR;
  char                    buf[MSL], *pwdnew;

  if(!(banker = find_banker(ch)))
  {
    send_to_char("You're not in a bank!\r\n", ch);
    return;
  }

  if(IS_NPC(ch))
  {
    snprintf(buf, MSL, "say Sorry, %s, we don't do business with mobs.", ch->name);
    interpret(banker, buf);
    return;
  }

  if(argument[0] == '\0')
  {
    send_to_char("Syntax: deposit amount currency\r\n", ch);
    interpret(banker, (char *)"say if you need help type &WHELP BANK&D.");
    return;
  }

  argument = one_argument(argument, arg1);
  argument = one_argument(argument, arg2);
  bank = find_bank(ch->pcdata->account);  // account saved to pfile

  if(is_number(arg1))
  {
    amount = atoi(arg1);
  }

  if(!bank)
  {
    send_to_char("There is no account by that name, use the account command to create a new account.\r\n", ch);
    return;
  }
  if(!is_number(arg1))
  {
    send_to_char("You can only deposit coins.\r\n", ch);
    return;
  }
  else
  {
    amount = atoi(arg1);
  }
  if(arg2)
    type = get_currency_type(arg2);

  if(type == CURR_NONE)
  {
    send_to_char("You don't have any of that kind of coin.\r\n", ch);
    return;
  }
  if(amount <= 0)
  {

    send_to_char("You can't do that.\r\n", ch);
    return;
  }
  if(amount > GET_MONEY(ch, type))
  {
    send_to_char("You don't have that much.\r\n", ch);
    return;
  }

  if(type != CURR_BRONZE && type != CURR_COPPER && type != CURR_GOLD && type != CURR_SILVER)
  {
    send_to_char("No such currency.\r\n", ch);
    return;
  }

  GET_MONEY(ch, type) -= amount;
  ch_printf(ch, "You put %d %s coins in the bank.\r\n", amount, curr_types[type]);

  if(type == CURR_BRONZE)
  {
    bank->bronze += amount;
    ch_printf(ch, "This brings your account's bronze balance to %d.\r\n", bank->bronze);
  }
  else if(type == CURR_COPPER)
  {
    bank->copper += amount;
    ch_printf(ch, "This brings your account's copper balance to %d.\r\n", bank->copper);
  }
  else if(type == CURR_GOLD)
  {
    bank->gold += amount;
    ch_printf(ch, "This brings your account's gold balance to %d.\r\n", bank->gold);
  }
  else if(type == CURR_SILVER)
  {
    bank->silver += amount;
    ch_printf(ch, "This brings your account's silver balance to %d.\r\n", bank->silver);
  }
  save_char_obj(ch);
  bank->lastused = current_time;
  save_bank();
  return;
}

void do_withdraw(CHAR_DATA *ch, char *argument)
{
  BANK_DATA              *bank;
  CHAR_DATA              *banker;
  char                    arg1[MIL];
  char                    arg2[MIL];
  int                     amount = 0, currtime = time(0);
  int                     type = DEFAULT_CURR;
  char                    buf[MSL], *pwdnew;

  if(!(banker = find_banker(ch)))
  {
    send_to_char("You're not in a bank!\r\n", ch);
    return;
  }

  if(IS_NPC(ch))
  {
    snprintf(buf, MSL, "say Sorry, %s, we don't do business with mobs.", ch->name);
    interpret(banker, buf);
    return;
  }

  if(argument[0] == '\0')
  {
    send_to_char("Syntax: withrdaw amount currency\r\n", ch);
    interpret(banker, (char *)"say if you need help type &WHELP BANK&D.");
    return;
  }

  argument = one_argument(argument, arg1);
  argument = one_argument(argument, arg2);
  bank = find_bank(ch->pcdata->account);  // account saved to pfile

  if(is_number(arg1))
  {
    amount = atoi(arg1);
  }

  if(!bank)
  {
    send_to_char("There is no account by that name, use the account command to create a new account.\r\n", ch);
    return;
  }
  if(!is_number(arg1))
  {
    send_to_char("You can only withdraw coins.\r\n", ch);
    return;
  }
  else
  {
    amount = atoi(arg1);
  }
  if(arg2)
    type = get_currency_type(arg2);
  if(type == CURR_NONE)
  {
    send_to_char("You don't have any of that kind of coin.\r\n", ch);
    return;
  }
  if(amount <= 0)
  {
    send_to_char("You can't do that.\r\n", ch);
    return;
  }
  if(type == CURR_BRONZE)
  {
    if(amount > bank->bronze)
    {
      ch_printf(ch, "You don't have that much %s in the bank.\r\n", curr_types[type]);
      return;
    }
    bank->bronze -= amount;
    ch_printf(ch, "This brings your account bronze balance to %d.\r\n", bank->bronze);
  }
  else if(type == CURR_COPPER)
  {
    if(amount > bank->copper)
    {
      ch_printf(ch, "You don't have that much %s in the bank.\r\n", curr_types[type]);
      return;
    }
    bank->copper -= amount;
    ch_printf(ch, "This brings your account copper balance to %d.\r\n", bank->copper);
  }
  else if(type == CURR_GOLD)
  {
    if(amount > bank->gold)
    {
      ch_printf(ch, "You don't have that much %s in the bank.\r\n", curr_types[type]);
      return;
    }
    bank->gold -= amount;
    ch_printf(ch, "This brings your account gold balance to %d.\r\n", bank->gold);
  }
  else if(type == CURR_SILVER)
  {
    if(amount > bank->silver)
    {
      ch_printf(ch, "You don't have that much %s in the bank.\r\n", curr_types[type]);
      return;
    }
    bank->silver -= amount;
    ch_printf(ch, "This brings your account silver balance to %d.\r\n", bank->silver);
  }
  else
  {
    send_to_char("No such currency.\r\n", ch);
    return;
  }
  GET_MONEY(ch, type) += amount;
  ch_printf(ch, "You took %d %s coins from the bank.\r\n", amount, curr_types[type]);
  bank->lastused = current_time;
  save_bank();
  save_char_obj(ch);
  return;
}

void free_bank_to_chars(BANK_DATA * bank)
{
  CHAR_DATA              *ch;

  if(!bank)
    return;

  for(ch = first_char; ch; ch = ch->next)
  {
    if(!ch || !ch->pcdata || !ch->pcdata->bank)
      continue;
    if(ch->pcdata->bank != bank)
      continue;
    ch_printf(ch, "%s account no longer exist.\r\n", bank->name);
    ch->pcdata->bank = NULL;
  }
}

void do_transfer(CHAR_DATA *ch, char *argument)
{
  BANK_DATA              *bank;
  BANK_DATA              *victim_bank;
  CHAR_DATA              *banker;
  char                    arg1[MIL], arg2[MIL], arg3[MIL];
  int                     amount = 0, currtime = time(0);
  int                     type = DEFAULT_CURR;
  char                    buf[MSL], *pwdnew;

  if(!(banker = find_banker(ch)))
  {
    send_to_char("You're not in a bank!\r\n", ch);
    return;
  }

  if(IS_NPC(ch))
  {
    snprintf(buf, MSL, "say Sorry, %s, we don't do business with mobs.", ch->name);
    interpret(banker, buf);
    return;
  }

  if(argument[0] == '\0')
  {
    send_to_char("Syntax: transfer amount currency destination\r\n", ch);
    interpret(banker, (char *)"say if you need help type &WHELP BANK&D.");
    return;
  }

  argument = one_argument(argument, arg1);
  argument = one_argument(argument, arg2);
  argument = one_argument(argument, arg3);
  bank = find_bank(ch->pcdata->account);  // account saved to pfile

  if(is_number(arg1))
  {
    amount = atoi(arg1);
  }

  if(!bank)
  {
    send_to_char("There is no account by that name, use the account command to create a new account.\r\n", ch);
    return;
  }

  if(!is_number(arg1))
  {
    send_to_char("You can only transfer coins.\r\n", ch);
    return;
  }
  else
  {
    amount = atoi(arg1);
  }
  if(arg1 && arg2)
    type = get_currency_type(arg2);

  if(type == CURR_NONE)
  {
    send_to_char("You don't have any of that kind of coin.\r\n", ch);
    return;
  }
  if(amount <= 0)
  {
    send_to_char("You can't do that.\r\n", ch);
    return;
  }
  victim_bank = find_bank(arg3);
  if(!victim_bank)
  {
    sprintf(buf, "%s There is no account by that name here.", ch->name);
    do_tell(banker, buf);
    return;
  }

  if(type == CURR_BRONZE)
  {
    if(amount > bank->bronze)
    {
      ch_printf(ch, "You don't have that much %s in the bank.\r\n", curr_types[type]);
      return;
    }

    bank->bronze -= amount;
    victim_bank->bronze += amount;
  }
  else if(type == CURR_COPPER)
  {
    if(amount > bank->copper)
    {
      ch_printf(ch, "You don't have that much %s in the bank.\r\n", curr_types[type]);
      return;
    }
    bank->copper -= amount;
    victim_bank->copper += amount;
  }
  else if(type == CURR_GOLD)
  {
    if(amount > bank->gold)
    {
      ch_printf(ch, "You don't have that much %s in the bank.\r\n", curr_types[type]);
      return;
    }
    bank->gold -= amount;
    victim_bank->gold += amount;
  }
  else if(type == CURR_SILVER)
  {
    if(amount > bank->silver)
    {
      ch_printf(ch, "You don't have that much %s in the bank.\r\n", curr_types[type]);
      return;
    }
    bank->silver -= amount;
    victim_bank->silver += amount;
  }
  ch_printf(ch, "You transfer %d %s coins from your account to theirs.\r\n", amount, curr_types[type]);
  bank->lastused = current_time;
  save_bank();
  return;

}