/
roa/
roa/lib/boards/
roa/lib/config/
roa/lib/edits/
roa/lib/help/
roa/lib/misc/
roa/lib/plrobjs/
roa/lib/quests/
roa/lib/socials/
roa/lib/www/
roa/lib/www/LEDSign/
roa/lib/www/LEDSign/fonts/
roa/lib/www/LEDSign/scripts/
roa/src/s_inc/
roa/src/sclient/
roa/src/sclient/binary/
roa/src/sclient/text/
roa/src/util/
/************************************************************************
	Realms of Aurealis 		James Rhone aka Vall of RoA

plshop.c				Code related to player owned
					shops as well as all the RoAOLC
					interfaces related to Online
					Player Shop Creation (OLPSC).

		******** 100% Completely Original Code ********
		*** BE AWARE OF ALL RIGHTS AND RESERVATIONS ***
		******** 100% Completely Original Code ********
		        All rights reserved henceforth. 

    Please note that no guarantees are associated with any code from
Realms of Aurealis.  All code which has been released to the general
public has been done so with an 'as is' pretense.  RoA is based on both
Diku and CircleMUD and ALL licenses from both *MUST* be adhered to as well
as the RoA license.   *** Read, Learn, Understand, Improve ***
*************************************************************************/
#include "conf.h"
#include "sysdep.h"

#include "structures.h"
#include "utils.h"
#include "comm.h"
#include "handler.h"
#include "acmd.h"
#include "db.h"
#include "mudlimits.h"
#include "interpreter.h"
#include "roaolc.h"
#include "lists.h"
#include "plshop.h"
#include "global.h"
#include "objsave.h"

// external functions...
extern char *get_name_by_id(int id);
extern void  perform_give(chdata *ch, chdata *vict, obdata *obj, BOOL calc_weight);

// external variables
extern dsdata *descriptor_list;
extern char *rcbits[];

// internal functions
ROA_MENU(plsedit_top_menu);
ROA_MENU(plsedit_confirm_quit);
ROA_MENU(plsedit_confirm_save);
ROA_MENU(plsedit_confirm_delete);

// internal variables
// for the types of plshops... not many yet
char *plshop_types[] = {
  "NORMAL",
  "PUBLIC",
  "\n"
};

char *plshop_bits[] = {
  "PLS_OPEN",
  "PLS_LANDTAX",
  "PLS_ITEMTAX",
  "PLS_LANDTAX_OWED",
  "\n"
};

// global variables
shlist topshops[TOP_PLSHOPS];

// return a ptr to the plshop with this ID
plshop *get_plshop_by_id(int id)
{
  plshop *ptr;

  for (ptr = pls_global; ptr; ptr=ptr->global_next)
    if (ptr->plshop_id == id)
      return ptr;

  return NULL;
}

BOOL owns_plshop(plshop *ptr, chdata *ch)
{
  return (ptr->owner_idnum == GET_IDNUM(ch));
}

// given a plshop ptr, insert it on global plshop list
void insert_plshop_to_world(plshop *ptr)
{
  ptr->global_next = pls_global;
  pls_global       = ptr;  
}

// given a plshop ptr, insert it on global plshop list
// note: this does not FREE the ptr
void remove_plshop_from_world(plshop *ptr)
{
  plshop *temp;

  REMOVE_FROM_LIST(ptr, pls_global, global_next);
}

// given a plshop ptr, insert it on chars plshop list
void insert_plshop_to_char(plshop *ptr, chdata *ch)
{
  ptr->next   = PLSHOPS(ch);
  PLSHOPS(ch) = ptr;  
  ptr->owner  = ch;
}

// given a plshop ptr, insert it on chars plshop list
void remove_plshop_from_char(plshop *ptr, chdata *ch)
{
  plshop *temp;

  REMOVE_FROM_LIST(ptr, PLSHOPS(ch), next);
  ptr->owner = NULL;
}

// remove every plshop from char's LL of plshops
void remove_char_plshops(chdata *ch)
{
  if (IS_NPC(ch)) return;

  while (PLSHOPS(ch))
    remove_plshop_from_char(PLSHOPS(ch), ch);
}

// when a player logs in, scan global LL of plshops and link them
// into players LL of plshops...
void load_plshops(chdata *ch)
{
  plshop *ptr;
  int rroom;

  if (IS_NPC(ch)) return;

  // just in case they have a list of em already...
  remove_char_plshops(ch);

  for (ptr = pls_global; ptr; ptr=ptr->global_next)
    if (owns_plshop(ptr, ch))
    {
      // first time send them header
      if (!PLSHOPS(ch))
      {
        send_to_char("\n\r%B%6Current Shop Accounts:%0\n\r",ch);
        send_to_char("%B%6-=-=-=-=-==-=-=-=-=-=-%0\n\r",ch);
      }

      insert_plshop_to_char(ptr, ch);

      if ((rroom = real_room(ptr->shop_rvnum)) > 0 && world[rroom].name)
        strcpy(buf2, world[rroom].name);
      else
        strcpy(buf2, "<Unknown>");

      sprintf(buf, "%%6Plshop #%%0%d (%s): %%B%%6%d%%0 %s.\n\r", ptr->plshop_id, 
              buf2, ptr->gold, currency_name_plural);
      S2C();
    }
}

// when a new plshop is created, we must be able to relink
// the players list of shops so they can access it...
ACMD(do_relink_plshops)
{
  char *argu = argument;
  chdata *vict;

  if (IS_NPC(ch))
    return;

  skip_spaces(&argu);
  if (!*argu)
  {
    send_to_char("Usage: pllink <PC name>.\n\r",ch);
    return;
  }  

  if (!(vict = get_char_vis(ch, argu)))
  {
    send_to_char("Victim not found.\n\r",ch);
    return;
  }

  if (IS_NPC(vict))
  {
    send_to_char("Usage: pllink <PC name>.\n\r",ch);
    return;
  }

  // the load function will unlink current list and relink
  load_plshops(vict); 
  send_to_char("Ok.\n\r",ch);
  send_to_char("%BPlshops relinked...%0\n\r",vict);
}

// given a file ptr and a ptr to allocated plrshop stucture, load from disk
void load_single_shop(FILE *fp, plshop *ptr)
{
  fscanf(fp, "%d %d %d %d\n", &ptr->owner_idnum, &ptr->shopkeep_vnum, &ptr->shop_rvnum, &ptr->gold);
  fscanf(fp, "%d %d %d\n", &ptr->type, &ptr->bitv, &ptr->rc_bitv);
  fscanf(fp, "%d %d %d\n", &ptr->minlevel, &ptr->maxlevel, &ptr->markup);
  fscanf(fp, "%d %d %d %d\n", &ptr->max_sell, &ptr->item_tax, &ptr->land_tax, &ptr->keeper_cut);
  fscanf(fp, "%d %d %d %d %d\n", &ptr->days_open, &ptr->averages[0], &ptr->averages[1], 
                                 &ptr->averages[2], &ptr->averages[3]);
  fscanf(fp, "%d %d %d %d %d\n", &ptr->item_tax_paid, &ptr->land_tax_paid, &ptr->keeper_paid,
                                 &ptr->gross_income, &ptr->net_income);

  ptr->gold_today = 0;
  ptr->next = NULL;		// set character next to NULL
}

// read in each shop, inserting it into global linked list
void boot_plshops(void)
{
  FILE *fp;
  struct stat s;
  plshop *ptr;
  int i, cnt;
  char fname[MAX_INPUT_LENGTH];

  for (i = 0, cnt = 0; i < MAX_PLSHOPS; i++)
  {
    sprintf(fname, "%s/%d.plshop", PLSHOP_DIR, i); 
    if (stat(fname, &s) < 0)
      continue;
    if (!(fp = fopen(fname, "rt")))
      continue;

    CREATE(ptr, plshop, 1);
    ptr->plshop_id = i;

    load_single_shop(fp, ptr);
    fclose(fp);
    
    // insert into global list
    ptr->global_next = pls_global;
    pls_global = ptr;

    cnt++;
  }
  
  sprintf(buf, "     %d Player Shops loaded", cnt);
  log(buf);
}

// given a file pointer and ptr to the shop to save
BOOL save_single_shop(FILE *fp, plshop *ptr)
{
  fprintf(fp, "%d %d %d %d\n", ptr->owner_idnum, ptr->shopkeep_vnum, ptr->shop_rvnum, ptr->gold);
  fprintf(fp, "%d %d %d\n", ptr->type, ptr->bitv, ptr->rc_bitv);
  fprintf(fp, "%d %d %d\n", ptr->minlevel, ptr->maxlevel, ptr->markup);
  fprintf(fp, "%d %d %d %d\n", ptr->max_sell, ptr->item_tax, ptr->land_tax, ptr->keeper_cut);
  fprintf(fp, "%d %d %d %d %d\n", ptr->days_open, ptr->averages[0], ptr->averages[1], 
                                 ptr->averages[2], ptr->averages[3]);
  fprintf(fp, "%d %d %d %d %d\n", ptr->item_tax_paid, ptr->land_tax_paid, ptr->keeper_paid,
                                 ptr->gross_income, ptr->net_income);

  return TRUE;
}

void save_plshops(void)
{
  FILE *fp;
  plshop *ptr;
  int cnt = 0;
  char fname[MAX_INPUT_LENGTH];
  chdata *mob;

  for (ptr = pls_global; ptr; ptr=ptr->global_next)
  {
    sprintf(fname, "%s/%d.plshop", PLSHOP_DIR, ptr->plshop_id); 
    if (!(fp = fopen(fname, "wt")))
      continue;
    save_single_shop(fp, ptr);
    cnt++;
    fclose(fp);
  } 

  sprintf(buf, "SYSUPD: %d plshops saved.", cnt);
  mudlog(buf, BUG, LEV_IMM, TRUE);

  // now save all the plshopkeeps...
  for (mob = character_list; mob; mob=mob->next)
    if (MOB_FLAGGED(mob, MOB_PLSHOPKEEP))
      save_plshopkeep_objs(mob);
}

// get the next available plshop_id based on what's in the
// current global list... return -1 if none available
int get_available_plshop_id(void)
{
  int i;

  for (i = 0; i < MAX_PLSHOPS; i++)
    if (!get_plshop_by_id(i))
      return i;

  return -1;
}

BOOL plshop_being_editted(plshop *ptr)
{
  dsdata *d = descriptor_list;

  for ( ; d; d=d->next)
    if (D_CHECK(d) && (PLS_EDITTED(d->character) == ptr))
      return TRUE;

  return FALSE;
}

//==================================================================
// User interface and misc dealings with Immortals and players...
//==================================================================

BOOL check_plshop_rcflags(chdata *ch, plshop *qptr)
{
  if (PLS_RCFLAGGED(qptr, PLS_NO_WARRIOR) && IS_NAT_WARRIOR(ch))
    return FALSE;
  if (PLS_RCFLAGGED(qptr, PLS_NO_CLERIC) && IS_NAT_CLERIC(ch))
    return FALSE;
  if (PLS_RCFLAGGED(qptr, PLS_NO_MAGE) && IS_NAT_MAGE(ch))
    return FALSE;
  if (PLS_RCFLAGGED(qptr, PLS_NO_THIEF) && IS_NAT_THIEF(ch))
    return FALSE;
  if (PLS_RCFLAGGED(qptr, PLS_NO_SHAMAN) && IS_NAT_SHAMAN(ch))
    return FALSE;
  if (PLS_RCFLAGGED(qptr, PLS_NO_RANGER) && IS_NAT_RANGER(ch))
    return FALSE;
  if (PLS_RCFLAGGED(qptr, PLS_NO_WARLOCK) && IS_NAT_WARLOCK(ch))
    return FALSE;
  if (PLS_RCFLAGGED(qptr, PLS_NO_BARD) && IS_NAT_BARD(ch))
    return FALSE;
  if (PLS_RCFLAGGED(qptr, PLS_NO_MONK) && IS_NAT_MONK(ch))
    return FALSE;
  if (PLS_RCFLAGGED(qptr, PLS_NO_MADEPT) && IS_NAT_MADEPT(ch))
    return FALSE;
  if (PLS_RCFLAGGED(qptr, PLS_NO_DRUID) && IS_NAT_DRUID(ch))
    return FALSE;


  if (PLS_RCFLAGGED(qptr, PLS_NO_HUMAN) && IS_HUMAN(ch))
    return FALSE;
  if (PLS_RCFLAGGED(qptr, PLS_NO_ELF) && IS_ELF(ch))
    return FALSE;
  if (PLS_RCFLAGGED(qptr, PLS_NO_HALF_ELF) && IS_HALF_ELF(ch))
    return FALSE;
  if (PLS_RCFLAGGED(qptr, PLS_NO_ORC) && IS_ORC(ch))
    return FALSE;
  if (PLS_RCFLAGGED(qptr, PLS_NO_OGRE) && IS_OGRE(ch))
    return FALSE;
  if (PLS_RCFLAGGED(qptr, PLS_NO_DROW) && IS_DROW(ch))
    return FALSE;
  if (PLS_RCFLAGGED(qptr, PLS_NO_DWARF) && IS_DWARF(ch))
    return FALSE;
  if (PLS_RCFLAGGED(qptr, PLS_NO_PIXIE) && IS_PIXIE(ch))
    return FALSE;
  if (PLS_RCFLAGGED(qptr, PLS_NO_NIXIE) && IS_NIXIE(ch))
    return FALSE;
  if (PLS_RCFLAGGED(qptr, PLS_NO_DRAGON) && IS_DRAGON(ch))
    return FALSE;
  return TRUE;
}

// show an immortal the global plshop list.. currently with very limited
// detail other than the plshop's ID and the owners ID and name
ACMD(do_plshoplist)
{
  char *p;
  plshop *ptr;
  int i;

  if (IS_NPC(ch))  return;

  strcpy(buf, "%B%6Current Player Owned Shops:%0\n\r"
              "%B%6-=-=-=-=-=-=-=-=-=-=-=-=-=-%0\n\r"
              "%B%5ID#   Owner (Name)%0\n\r"
              "%B%6-=-=-=-=-=-=-=-=-=-=-=-=-=-%0\n\r");

  for (i = 0; i < MAX_PLSHOPS; i++)
    if ((ptr = get_plshop_by_id(i)))
    {
      p = get_name_by_id(ptr->owner_idnum); 
      sprintf(buf2, "%s", p ? p : "<UNKNOWN>");   
      sprintf(buf+strlen(buf),"%-3d - %5d (%s)\n\r",i,ptr->owner_idnum,buf2);
    }

  page_string(ch->desc, buf, 1);
}

// show stats of a particular shop
ACMD(do_plshopstat)
{
  char *argu = argument, *p;
  int id;
  plshop *s;

  if (IS_NPC(ch))  return;

  skip_spaces(&argu);
  if (!*argu || !is_number(argu))
  {
    send_to_char("Usage: plshopstat <plshop ID>.\n\r",ch);
    return;
  }

  id = atoi(argu);
  if (!(s = get_plshop_by_id(id)))
  {
    send_to_char("Unable to locate a plshop with that ID.\n\r",ch);
    return;
  }

  // ok, we have ptr to the shop...send stats
  sprintf(buf, "%%B%%6Player Shop Stats for ShopID#%%0: %d\n\r", s->plshop_id); S2C();
  p = get_name_by_id(s->owner_idnum); 
  sprintf(buf2, "%s", p ? p : "<UNKNOWN>");   
  sprintf(buf, "%%6OwnerID#%%0: %d (%s)\n\r",  s->owner_idnum, buf2); S2C();
  sprintf(buf, "%%6Shopkeep Vnum%%0: %d\n\r",  s->shopkeep_vnum); S2C();
  sprintf(buf, "%%6Shop Room Vnum%%0: %d\n\r", s->shop_rvnum); S2C();
  sprinttype(PLS_TYPE(s), plshop_types, buf2);
  sprintf(buf, "%%6Shop Type%%0: %%5%s%%0\n\r", buf2); S2C();
  sprintbit(PLS_FLAGS(s), plshop_bits, buf2);
  sprintf(buf, "%%6Shop Flags%%0: %%5%s%%0\n\r", buf2); S2C();
  sprintbit(PLS_RCFLAGS(s), rcbits, buf2);
  sprintf(buf, "%%6Shop RC Flags%%0: %%5%s%%0\n\r", buf2); S2C();
  sprintf(buf, "%%6Shop Minlevel | MaxLevel%%0: %d | %d\n\r", s->minlevel, s->maxlevel); S2C();
  sprintf(buf, "%%6Max Simultaneous Items to Sell%%0: %d\n\r", s->max_sell); S2C();
  if (PLS_FLAGGED(s, PLS_ITEMTAX))
  {
    sprintf(buf, "%%6Item Tax (percentage of item gross)%%0: %d\n\r", s->item_tax); S2C();
  }
  if (PLS_FLAGGED(s, PLS_LANDTAX))
  {
    sprintf(buf, "%%6Property Tax (monthly charge)%%0: %d\n\r", s->land_tax); S2C();
  }
  sprintf(buf, "%%6Shopkeep's Cut (percentage of item gross)%%0: %d\n\r", s->keeper_cut); S2C();
  sprintf(buf, "%%6Owner's Markup (percentage of item gross)%%0: %d\n\r", s->markup); S2C();
  sprintf(buf, "%%6Days Open%%0: %d\n\r", s->days_open); S2C();
  sprintf(buf, "%%6Account%%0: %d\n\r", s->gold); S2C();
  sprintf(buf, "%%6Amount Sold Today%%0: %d\n\r", s->gold_today); S2C();
  sprintf(buf, "%%6Total Gross Income | Total Net Income%%0: %d | %d\n\r", 
          s->gross_income, s->net_income); S2C();
  sprintf(buf, "%%6Total Keeper Cut%%0: %d\n\r", s->keeper_paid); S2C();
  sprintf(buf, "%%6Total Item Taxes Paid%%0: %d\n\r", s->item_tax_paid); S2C();
  sprintf(buf, "%%6Total Property Taxes Paid%%0: %d\n\r", s->land_tax_paid); S2C();
  sprintf(buf, "%%6Sale Averages Per Day | Week | Month | Year%%0: %d | %d | %d | %d\n\r", 
          PLS_PERDAY(s),PLS_PERWEEK(s),PLS_PERMONTH(s),PLS_PERYEAR(s)); S2C();

}

// for qsort
int sort_shops(const void *first, const void *second)
{
  shlist *one, *two;

  one = (shlist *) first;
  two = (shlist *) second;

  if (one->gross_income < two->gross_income)
    return 1;
  else
  if (one->gross_income > two->gross_income)
    return -1;
  else
    return 0;
}

// wipe the topshop array
void clear_topshops(void)
{
  memset( (char *)&topshops, 0, sizeof(topshops));
}

// return the index of the lowest value in the topshop array
int get_lowest_in_topshops(void)
{
  int lowindex = 0;
  int i;

  for (i=0; i < TOP_PLSHOPS; i++)
    if (topshops[i].gross_income <= topshops[lowindex].gross_income)
      lowindex = i;
  return lowindex; 
}

// go thru linked list, fill in topshop array
void fill_topshops(void)
{
  plshop *ptr;
  int low;

  for (ptr = pls_global; ptr; ptr=ptr->global_next)
  {
    low = get_lowest_in_topshops();
    if (ptr->gross_income > topshops[low].gross_income)
    {
      topshops[low].shop_id = ptr->plshop_id;
      topshops[low].gross_income = ptr->gross_income;
    }
  }

}

// show immortal the top 20 shops in order based on most gross_income
ACMD(do_topshops)
{
  int i;
  plshop *ptr;
  char *p;
  BOOL found = FALSE;

  clear_topshops();
  fill_topshops();
  qsort((void *) topshops, TOP_PLSHOPS, sizeof(shlist), sort_shops);

  strcpy(buf, "%B%6Top Player Shops by Gross Income%0:\n\r");
  strcat(buf, "%B%6-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-%0\n\r");
  for(i = 0; i < TOP_PLSHOPS && topshops[i].gross_income > 0; i++)
  {
    ptr = get_plshop_by_id(topshops[i].shop_id);
    if (!ptr)
      break;

    found = TRUE;
    p = get_name_by_id(ptr->owner_idnum); 
    sprintf(buf2, "%s", p ? p : "<UNKNOWN>");   
    sprintf(buf+strlen(buf),"%%5Shop ID#%%0:%-3d - %d %%5%s%%0 (%s)\n\r", ptr->plshop_id, 
            ptr->gross_income, currency_name_plural, buf2);
  }

  if (!found)
    strcat(buf, "%B%1No qualifying shops...%0\n\r");

  page_string(ch->desc, buf, 1);
}

// immortal ability to allocate new plshop, insert into list
// and get thrown into plshop menu
ACMD(do_plshopcreate)
{
  plshop *ptr;
  int id;

  if (IS_NPC(ch))  return;

  id = get_available_plshop_id();
  if (id < 0)
  {
    mudlog("SYSERR: Unable to get available plshop ID.", BRF, LEV_IMM, TRUE);
    return;
  }  
  
  // ok allocate, assign, insert...
  CREATE(ptr, plshop, 1);
  ptr->plshop_id = id;
  insert_plshop_to_world(ptr);

  // now send them into the menu...
  PLS_EDITTED(ch) = ptr;

  SET_BIT(PLR_FLAGS(ch), PLR_BUILDING);
  MENU_DEPTH(ch) = 0;
  ch->pc_specials->field_changed = FALSE;
  menu_jump(ch, plsedit_top_menu);
}

ACMD(do_plshopedit)
{
  char *argu = argument;
  int id;
  plshop *ptr;

  if (IS_NPC(ch))  return;

  skip_spaces(&argu);
  if (!*argu || !is_number(argu))
  {
    send_to_char("Usage: plshopedit <plshop ID>.\n\r",ch);
    return;
  }

  id = atoi(argu);
  if (!(ptr = get_plshop_by_id(id)))
  {
    send_to_char("Unable to locate a plshop with that ID.\n\r",ch);
    return;
  }

  SET_BIT(PLR_FLAGS(ch), PLR_BUILDING);
  MENU_DEPTH(ch) = 0;
  ch->pc_specials->field_changed = FALSE;

  PLS_EDITTED(ch) = ptr;
  menu_jump(ch, plsedit_top_menu);
}

ACMD(do_plshopsave)
{
  if (IS_NPC(ch))  return;

  save_plshops();
  send_to_char("Ok.\n\r",ch);
}

ACMD(do_plshopdelete)
{
  char *argu = argument;
  int id;
  plshop *ptr;

  if (IS_NPC(ch))  return;

  skip_spaces(&argu);
  if (!*argu || !is_number(argu))
  {
    send_to_char("Usage: plshopdelete <plshop ID>.\n\r",ch);
    return;
  }

  id = atoi(argu);
  if (!(ptr = get_plshop_by_id(id)))
  {
    send_to_char("Unable to locate a plshop with that ID.\n\r",ch);
    return;
  }

  PLS_EDITTED(ch) = ptr;
  menu_jump(ch, plsedit_confirm_delete);
}

//==================================================================
// Mortal interface to player shops...
// Started 1/18/98... 
//==================================================================

plshop *get_shopkeeps_plshop(int mvnum)
{
  plshop *ptr;

  if (real_mobile(mvnum) < 0)
    return NULL;

  for (ptr = pls_global; ptr; ptr = ptr->global_next)
    if (ptr->shopkeep_vnum == mvnum)
      return ptr;

  return NULL;
}

// return ptr to shop if char standing in their own shop?
plshop *in_own_shop(chdata *ch)
{
  plshop *ptr;

  if (INVALID_ROOM(ch->in_room))
    return NULL;

  for (ptr = PLSHOPS(ch); ptr; ptr = ptr->next)
    if (world[ch->in_room].number == ptr->shop_rvnum)
      return ptr;

  return NULL;
}

// deposit gumbas into this shop's account...
ACMD(do_shopdeposit)
{
  plshop *ptr;
  int amount;

  if (IS_NPC(ch)) return;

  if (!(ptr = in_own_shop(ch)))
  {
    send_to_char("You must be located in your shop to access its account.\n\r",ch);
    return;
  }  

  one_argument(argument, arg);
  if (!arg || !*arg || !is_number(arg))
  {
    send_to_char("Usage: shopdeposit < amount >.\n\r",ch);
    return;
  }

  amount = atoi(arg);
  if (amount <= 0)
  {
    send_to_char("Usage: shopdeposit < amount >.\n\r",ch);
    return;
  }  

  if (amount > GET_GOLD(ch))
  {
    sprintf(buf, "You don't have that many %s on hand.\n\r", currency_name_plural);
    S2C();
    return;
  }

  ptr->gold += amount;
  GET_GOLD(ch) -= amount;

  sprintf(buf, "%%6Amount deposited%%0: %d\n\r%%6New Shop Balance%%0: %d\n\r", amount, ptr->gold);
  S2C();
}

// withdraw gumbas into this shop's account...
ACMD(do_shopwithdraw)
{
  plshop *ptr;
  int amount;

  if (IS_NPC(ch)) return;

  if (!(ptr = in_own_shop(ch)))
  {
    send_to_char("You must be located in your shop to access its account.\n\r",ch);
    return;
  }

  one_argument(argument, arg);
  if (!arg || !*arg || !is_number(arg))
  {
    send_to_char("Usage: shopwithdraw < amount >.\n\r",ch);
    return;
  }

  amount = atoi(arg);
  if (amount <= 0)
  {
    send_to_char("Usage: shopwithdraw < amount >.\n\r",ch);
    return;
  }

  if (amount > ptr->gold)
  {
    sprintf(buf, "You don't have that many %s in this shop's account.\n\r", currency_name_plural);
    S2C();
    return;
  }

  ptr->gold -= amount;
  GET_GOLD(ch) += amount;

  sprintf(buf, "%%6Amount withdrawn%%0: %d\n\r%%6New Shop Balance%%0: %d\n\r", amount, ptr->gold);
  S2C();
}

// let player open a shop
ACMD(do_shopopen)
{
  plshop *ptr;

  if (IS_NPC(ch)) return;

  if (!(ptr = in_own_shop(ch)))
  {
    send_to_char("You must be located in your shop to open it.\n\r",ch);
    return;
  }

  if (PLS_FLAGGED(ptr, PLS_OPEN))
  {
    send_to_char("This shop is already open.\n\r",ch);
    return;
  }

  SET_BIT(PLS_FLAGS(ptr), PLS_OPEN);
  send_to_char("Ok. Shop now flagged OPEN.\n\r",ch);
}

// let player close a shop
ACMD(do_shopclose)
{
  plshop *ptr;

  if (IS_NPC(ch)) return;

  if (!(ptr = in_own_shop(ch)))
  {
    send_to_char("You must be located in your shop to close it.\n\r",ch);
    return;
  }

  if (!PLS_FLAGGED(ptr, PLS_OPEN))
  {
    send_to_char("This shop is already closed.\n\r",ch);
    return;
  }

  REMOVE_BIT(PLS_FLAGS(ptr), PLS_OPEN);
  send_to_char("Ok. Shop now flagged CLOSED.\n\r",ch);
}

// account of all shop accounts for player
ACMD(do_plshopbank)
{
  plshop *ptr;
  int rroom;

  if (IS_NPC(ch)) return;

  for (ptr = PLSHOPS(ch); ptr; ptr=ptr->next)
  {
    // first time send them header
    if (ptr == PLSHOPS(ch))
    {
      send_to_char("\n\r%B%6Current Shop Accounts:%0\n\r",ch);
      send_to_char("%B%6-=-=-=-=-==-=-=-=-=-=-%0\n\r",ch);
    }

    if ((rroom = real_room(ptr->shop_rvnum)) > 0)
      strcpy(buf2, world[rroom].name);
    else
      strcpy(buf2, "<Unknown>");

    sprintf(buf, "%%6Plshop #%%0%d (%s): %%B%%6%d%%0 %s.\n\r", ptr->plshop_id, 
            buf2, ptr->gold, currency_name_plural);
    S2C();
  }
}

// let player edit some of the stuff on their shops... 
ACMD(do_mort_plshopedit)
{
  plshop *s;

  if (IS_NPC(ch)) return;

  if (!(s = in_own_shop(ch)))
  {
    send_to_char("You must be located in your shop to edit it.\n\r",ch);
    return;
  }

  SET_BIT(PLR_FLAGS(ch), PLR_BUILDING);
  MENU_DEPTH(ch) = 0;
  ch->pc_specials->field_changed = FALSE;

  PLS_EDITTED(ch) = s;
  menu_jump(ch, plsedit_top_menu);
}

// let player get good stats on each plshop they own
ACMD(do_shopstats)
{
  plshop *s;
  char *p;

  if (IS_NPC(ch)) return;

  if (!(s = in_own_shop(ch)))
  {
    send_to_char("You must be located in your shop to get its stats.\n\r",ch);
    return;
  }

  // ok, we have ptr to the shop...send stats
  sprintf(buf, "%%B%%6Player Shop Stats for ShopID#%%0: %d\n\r", s->plshop_id); S2C();
  p = get_name_by_id(s->owner_idnum);
  sprintf(buf2, "%s", p ? p : "<UNKNOWN>");
  sprintf(buf, "%%6OwnerID#%%0: %d (%s)\n\r",  s->owner_idnum, buf2); S2C();
  sprinttype(PLS_TYPE(s), plshop_types, buf2);
  sprintf(buf, "%%6Shop Type%%0: %%5%s%%0\n\r", buf2); S2C();
  sprintbit(PLS_FLAGS(s), plshop_bits, buf2);
  sprintf(buf, "%%6Shop Flags%%0: %%5%s%%0\n\r", buf2); S2C();
  sprintbit(PLS_RCFLAGS(s), rcbits, buf2);
  sprintf(buf, "%%6Shop RC Flags%%0: %%5%s%%0\n\r", buf2); S2C();
  sprintf(buf, "%%6Shop Minlevel | MaxLevel%%0: %d | %d\n\r", s->minlevel, s->maxlevel); S2C();
  sprintf(buf, "%%6Max Simultaneous Items to Sell%%0: %d\n\r", s->max_sell); S2C();
  if (PLS_FLAGGED(s, PLS_ITEMTAX))
  {
    sprintf(buf, "%%6Item Tax (percentage of item gross)%%0: %d\n\r", s->item_tax); S2C();
  }
  if (PLS_FLAGGED(s, PLS_LANDTAX))
  {
    sprintf(buf, "%%6Property Tax (monthly charge)%%0: %d\n\r", s->land_tax); S2C();
  }
  sprintf(buf, "%%6Shopkeep's Cut (percentage of item gross)%%0: %d\n\r", s->keeper_cut); S2C();
  sprintf(buf, "%%6Owner's Markup (percentage of item gross)%%0: %d\n\r", s->markup); S2C();
  sprintf(buf, "%%6Days Open%%0: %d\n\r", s->days_open); S2C();
  sprintf(buf, "%%6Account%%0: %d\n\r", s->gold); S2C();
  sprintf(buf, "%%6Amount Sold Today%%0: %d\n\r", s->gold_today); S2C();
  sprintf(buf, "%%6Total Gross Income | Total Net Income%%0: %d | %d\n\r",
          s->gross_income, s->net_income); S2C();
  sprintf(buf, "%%6Total Keeper Cut%%0: %d\n\r", s->keeper_paid); S2C();
  sprintf(buf, "%%6Total Item Taxes Paid%%0: %d\n\r", s->item_tax_paid); S2C();
  sprintf(buf, "%%6Total Property Taxes Paid%%0: %d\n\r", s->land_tax_paid); S2C();
  sprintf(buf, "%%6Sale Averages Per Day | Week | Month | Year%%0: %d | %d | %d | %d\n\r",
          PLS_PERDAY(s),PLS_PERWEEK(s),PLS_PERMONTH(s),PLS_PERYEAR(s)); S2C();
}

// if in own shop and shopkeep mob is present, give item to mob to sell
ACMD(do_shopgive)
{
  plshop *s;
  chdata *mob;
  obdata *obj, *next_obj;
  int dotmode, i;

  if (IS_NPC(ch)) return;

  if (!(s = in_own_shop(ch)))
  {
    send_to_char("You must be located in your shop.\n\r",ch);
    return;
  }

  // ok, we have ptr to the shop...now find shopkeep...
  for (mob = world[ch->in_room].people; mob; mob = mob->next_in_room)
    if (MOB_FLAGGED(mob, MOB_PLSHOPKEEP) && GET_MOB_VNUM(mob) == s->shopkeep_vnum)
      break;

  if (!mob)
  {
    send_to_char("Your shopkeep must be present.\n\r",ch);
    return;
  }

  one_argument(argument, arg);
  if (!arg || !*arg)
  {
    send_to_char("Shopgive what?\n\r",ch);
    return;
  }

  i = inv_count(mob->carrying);

  if (i >= s->max_sell)
  {
    act("$N is sellng as much as $E can.", TRUE, ch, 0, mob, TO_CHAR);
    return;
  }

  dotmode = find_all_dots(arg);
  if (dotmode == FIND_ALL)
  {
    if (!ch->carrying)
       send_to_char("You don't seem to be holding anything.\n\r", ch);
    else
    for (obj = ch->carrying; obj; obj = next_obj) 
    {
       next_obj = obj->next_content;

       // yes.. there is a limit
       if (++i <= s->max_sell)
         perform_give(ch, mob, obj, FALSE);
       else
         break;
    }
  }
  else
  if (dotmode == FIND_ALLDOT)
  {
    if (!*arg) 
    {
      send_to_char("All of what?\n\r", ch);
      return;
    }

    if (!(obj = get_obj_in_list_vis(ch, arg, ch->carrying))) 
    {
      sprintf(buf, "You don't seem to have any %ss.\n\r", arg);
      S2C();
    }
    else
    while (obj) 
    {
      next_obj = get_obj_in_list_vis(ch, arg, obj->next_content);
      // yes.. there is a limit
      if (++i <= s->max_sell)
        perform_give(ch, mob, obj, FALSE);
      else
        break;
      obj = next_obj;
    }
  }
  else
  {
    if (!(obj = get_obj_in_list_vis(ch, arg, ch->carrying)))
    {
      sprintf(buf, "You don't seem to have %s %s.\n\r", AN(arg), arg);
      S2C();
    } 
    else
    if (++i <= s->max_sell)
      perform_give(ch, mob, obj, FALSE);
  }
}

// if in own shop and shopkeep mob is present, take item from mob 
ACMD(do_shoptake)
{
  plshop *s;
  chdata *mob;
  obdata *obj, *next_obj;
  int dotmode;

  if (IS_NPC(ch)) return;

  if (!(s = in_own_shop(ch)))
  {
    send_to_char("You must be located in your shop.\n\r",ch);
    return;
  }

  // ok, we have ptr to the shop...now find shopkeep...
  for (mob = world[ch->in_room].people; mob; mob = mob->next_in_room)
    if (MOB_FLAGGED(mob, MOB_PLSHOPKEEP) && GET_MOB_VNUM(mob) == s->shopkeep_vnum)
      break;

  if (!mob)
  {
    send_to_char("Your shopkeep must be present.\n\r",ch);
    return;
  }

  one_argument(argument, arg);
  if (!arg || !*arg)
  {
    send_to_char("Shoptake what?\n\r",ch);
    return;
  }

  dotmode = find_all_dots(arg);
  if (dotmode == FIND_ALL)
  {
    if (!mob->carrying)
      act("$N doesn't seem to be carrying anything.", FALSE, ch, 0, mob, TO_CHAR);
    else
    for (obj = mob->carrying; obj; obj = next_obj) 
    {
       next_obj = obj->next_content;
       perform_give(mob, ch, obj, FALSE);
    }
  }
  else
  if (dotmode == FIND_ALLDOT)
  {
    if (!*arg) 
    {
      send_to_char("All of what?\n\r", ch);
      return;
    }

    if (!(obj = get_obj_in_list_vis(mob, arg, mob->carrying))) 
    {
      sprintf(buf, "$N doesn't seem to have any %ss.", arg);
      act(buf, FALSE, ch, 0, mob, TO_CHAR);
    }
    else
    while (obj) 
    {
      next_obj = get_obj_in_list_vis(mob, arg, obj->next_content);
      perform_give(mob, ch, obj, FALSE);
      obj = next_obj;
    }
  }
  else
  {
    if (!(obj = get_obj_in_list_vis(mob, arg, mob->carrying)))
    {
      sprintf(buf, "$N doesn't seem to have %s %s.\n\r", AN(arg), arg);
      act(buf, FALSE, ch, 0, mob, TO_CHAR);
    } 
    else
      perform_give(mob, ch, obj, FALSE);
  }
}

// save a mob's inventory list to disk
void save_plshopkeep_objs(chdata *mob)
{
  FILE *fp;
  char fname[MAX_INPUT_LENGTH];

  if (!MOB_FLAGGED(mob, MOB_PLSHOPKEEP))
    return;

  sprintf(fname, "plshops/%d.plshopkeep", GET_MOB_VNUM(mob));

  if (!mob->carrying)
  {
    unlink(fname);
    return;
  }

  if (!(fp = fopen(fname, "w"))) {
    sprintf(buf, "SYSERR: Error opening plshopkeep file %d.plshopkeep",GET_MOB_VNUM(mob));
    mudlog(buf, BRF, LEV_IMM, TRUE);
    return;
  }

  if (inv_count(mob->carrying) > MAX_SIMUL)
  {
    sprintf(buf, "%%1WARNING%%0: Max simultaneous items (%d) exceeded.\n\r"
                 "Plshopkeep inventory not saved.\n\r", MAX_SIMUL);
    send_to_room(buf, mob->in_room);
    fclose(fp);
    return;
  }

  // cannot save non rentables in file...
  extract_norents(mob->carrying);

  // check one more time just so we're not calling a function for no reason
  // if the room only had norents, now it has nothing, remove file and return
  if (!mob->carrying)
  {
    fclose(fp);
    unlink(fname);
    return;
  }

  // save_object is recursive, just send the first object in the list
  // re: objsave.c
  if (!save_object(mob->carrying, fp))
  {
    fclose(fp);
    send_to_room("Error saving plshopkeep inventory, notify an immortal...\n\r",mob->in_room);
    return;
  }

  fclose(fp);
  send_to_room("Saving plshopkeep...\n\r", mob->in_room);

  sprintf(buf, "SYSUPD: Plshopkeep #%d saved.", GET_MOB_VNUM(mob));
  mudlog(buf, BUG, LEV_IMM, FALSE);
}

// give a mob, load it's objects 
BOOL load_plshopkeep_objs(chdata *mob)
{
  FILE *fp;
  char fname[MAX_STRING_LENGTH];
  obdata *obj = NULL;
  int tmp;

  if (!MOB_FLAGGED(mob, MOB_PLSHOPKEEP))
  {
    sprintf(buf, "SYSERR: Invalid plshopkeep mob (%s).", GET_NAME(mob));
    mudlog(buf, NRM, LEV_IMM, TRUE);
    return FALSE;
  }

  sprintf(fname, "plshops/%d.plshopkeep", GET_MOB_VNUM(mob));
  if (!(fp = fopen(fname, "rt")))
  {
    if (errno != ENOENT)
    {
      sprintf(buf, "SYSERR: Plshopkeep (#%d) object loading error.", GET_MOB_VNUM(mob));
      mudlog(buf, NRM, LEV_IMM, TRUE);
    }
    return FALSE;
  }

  // wipe anything that it currently has...
  extract_objects(mob->carrying);

  /* read objects here, restore saved stats, give em to mob */
  while (!feof(fp))
  {
    fscanf(fp, "%d", &tmp);
    if (real_object(tmp) < 0)  /* skip it, shouldnt be here */
    {
      fgets(buf, 80, fp); /* skip this line */
      continue;
    }
    else  /* lets read this puppy */
    {
        obj = read_object(tmp, VIRTUAL);
        fscanf(fp, "%d %d %d %d %d %d %d %d %d %d %d %d\n",
                &obj->value[0], &obj->value[1], &obj->value[2], &obj->value[3],
                &obj->objsave_parent, &obj->tmp1, &obj->objsave_self,
                &obj->tmp2, &obj->objsave_where,
                &obj->obj_hits, &obj->owner_of, &obj->obj_id);
        obj_to_char(obj, mob);
      }
   }
   fclose(fp);
   return TRUE;
}

//==================================================================
// Plshop updates over time...
//==================================================================
void daily_plshop_update(void)
{
  plshop *s;
  int days;

  for (s = pls_global; s; s=s->global_next)
  {
    s->gross_income += s->gold_today;
    s->gold_today = 0;

    days = ++s->days_open;
    if (days)
      s->averages[PERDAY] = s->gross_income/days;
  }
}

// every month, cals normal numbers, but also take land tax
// if it's flagged as such
void monthly_plshop_update(void)
{
  plshop *s;
  int days, weeks, months;

  for (s = pls_global; s; s=s->global_next)
  {
    days = s->days_open;
    weeks = days/7;
    months = weeks/4;

    if (weeks)
      s->averages[PERWEEK] = s->gross_income/weeks;

    if (months)
      s->averages[PERMONTH] = s->gross_income/months;

    if (PLS_FLAGGED(s, PLS_LANDTAX))
    {
      // everything is coooolll
      if (s->gold >= s->land_tax)
      {
        s->land_tax_paid += s->land_tax;
        s->gold -= s->land_tax;
      }
      else // uh oh, if it is flagged... syslog it
      {
        if (PLS_FLAGGED(s, PLS_LANDTAX_OWED))
        {
          sprintf(buf, "SYSUPD: Plshop #%d unable to pay land tax (%d).", s->plshop_id, s->land_tax);
          mudlog(buf, BRF, LEV_IMM, TRUE);
        }

        SET_BIT(PLS_FLAGS(s), PLS_LANDTAX_OWED);
        if (s->gold > 0)
          s->land_tax_paid += s->land_tax - s->gold;

        // YES will go into the hole...
        s->gold -= s->land_tax;
      }
    }
  }
}

void yearly_plshop_update(void)
{
  plshop *s;
  int days, weeks, months, years;

  for (s = pls_global; s; s=s->global_next)
  {
    days   = s->days_open;
    weeks  = days/7;
    months = weeks/4;
    years  = months/16;

    if (years)
      s->averages[PERYEAR] = s->gross_income/years;
  }
}

//==================================================================
//
// RoA OLPSC (Online Player Shop Creation) 
// 
// Started 12/23/97 (and all through the house...not a creature was
//                   stirring, except that damn trackball and that
//                   annoying extra-click keyboard... -jtrhone)
//==================================================================

ROA_MENU(plsedit_top_menu)
{
  char *p;
  int field;
  plshop *s = PLS_EDITTED(ch);

  if (!input_str)
  {
    menu_title_send("PlayerShopEdit Main Menu", ch);
    sprintf(buf, " X.) %%6Shop ID#%%0: %d\n\r", s->plshop_id); S2C();

   if (IS_AIMP(ch))
   {
    p = get_name_by_id(s->owner_idnum); 
    sprintf(buf2, "%s", p ? p : "<UNKNOWN>");   

    sprintf(buf, " 1.) %%6OwnerID#%%0: %d (%s)\n\r",  s->owner_idnum, buf2); S2C();
    sprintf(buf, " 2.) %%6Shopkeep Vnum%%0: %d\n\r",  s->shopkeep_vnum); S2C();
    sprintf(buf, " 3.) %%6Shop Room Vnum%%0: %d\n\r", s->shop_rvnum); S2C();

    sprinttype(PLS_TYPE(s), plshop_types, buf2);
    sprintf(buf, " 4.) %%6Shop Type%%0: %%5%s%%0\n\r", buf2); S2C();

    sprintbit(PLS_FLAGS(s), plshop_bits, buf2);
    sprintf(buf, " 5.) %%6Shop Flags%%0: %%5%s%%0\n\r", buf2); S2C();
   }

    sprintbit(PLS_RCFLAGS(s), rcbits, buf2);
    sprintf(buf, " 6.) %%6Shop RC Flags%%0: %%5%s%%0\n\r", buf2); S2C();

    sprintf(buf, " 7.) %%6Shop Minlevel%%0: %d\n\r", s->minlevel); S2C();
    sprintf(buf, " 8.) %%6Shop Maxlevel%%0: %d\n\r", s->maxlevel); S2C();

   if (IS_AIMP(ch))
   {
    sprintf(buf, " 9.) %%6Max Simultaneous Items to Sell%%0: %d\n\r", s->max_sell); S2C();

    if (PLS_FLAGGED(s, PLS_ITEMTAX))
    {
      sprintf(buf, "10.) %%6Item Tax (percentage of item gross)%%0: %d\n\r", s->item_tax); S2C();
    }

    if (PLS_FLAGGED(s, PLS_LANDTAX))
    {
      sprintf(buf, "11.) %%6Property Tax (monthly charge)%%0: %d\n\r", s->land_tax); S2C();
    }

    sprintf(buf, "12.) %%6Shopkeep's Cut (percentage of item gross)%%0: %d\n\r", s->keeper_cut); S2C();
   }

    sprintf(buf, "13.) %%6Owner's Markup (percentage of item gross)%%0: %d\n\r", s->markup); S2C();

   if (IS_AIMP(ch))
   {
    sprintf(buf, "14.) %%6Days Open (do not edit)%%0: %d\n\r", s->days_open); S2C();

    sprintf(buf, "15.) %%6Account (do not edit)%%0: %d\n\r", s->gold); S2C();
   }

    send_to_char("\n\r", ch);
    MENU_PROMPT(ch) = "Enter field number to change or 0 to end: ";
    return;
  }

  strcpy(buf, input_str);
  p = strtok(buf, "   \n\r");
  if (p)
    field = atoi(p);
  else
    field = 0;

  // don't let morts do certain options...
  if (!IS_AIMP(ch) && field != 0 && field != 6 && field != 7 && field != 8 && field != 13)
    field = 99;
  
  switch (field)
  {
    case 0:
      menu_jump(ch, plsedit_confirm_quit);
      break;

    case 1:
      GET_INTEGER_ARG(ch, "Enter Owner ID#: ", s->owner_idnum, 0, 99999);
      break;

    case 2:
      GET_INTEGER_ARG(ch, "Enter Shopkeep Vnum: ", s->shopkeep_vnum, 0, 99999);
      break;

    case 3:
      GET_INTEGER_ARG(ch, "Enter Plshop Room Vnum: ", s->shop_rvnum, 0, 99999);
      break;

    case 4:
      get_integer_list(ch, "Enter number of the desired type: ", 
                       &s->type, sizeof(s->type), plshop_types);
      break;

    case 5:
      toggle_menu(ch, "Enter plshop bit to toggle: ", &s->bitv, plshop_bits);
      break;

    case 6:
      toggle_menu(ch, "Enter plshop rcbit to toggle: ", &s->rc_bitv, rcbits);
      break;

    case 7:
      GET_INTEGER_ARG(ch, "Enter Plshop Minlevel: ", s->minlevel, 0, LEV_IMM);
      break;

    case 8:
      GET_INTEGER_ARG(ch, "Enter Plshop Maxlevel: ", s->maxlevel, 0, LEV_IMM);
      break;

    case 9:
      GET_INTEGER_ARG(ch, "Enter Max Simultaneous Items to Sell: ", s->max_sell, 0, 50);
      break;

    case 10:
      if (PLS_FLAGGED(s, PLS_ITEMTAX))
      {
        GET_INTEGER_ARG(ch, "Enter Per Item Tax: ", s->item_tax, 0, 99);
      }
      break;

    case 11:
      if (PLS_FLAGGED(s, PLS_LANDTAX))
      {
        GET_INTEGER_ARG(ch, "Enter Monthly Property Tax: ", s->land_tax, 0, 32767);
      }
      break;

    case 12:
      GET_INTEGER_ARG(ch, "Enter Shopkeep's Cut: ", s->keeper_cut, 0, 99);
      break;

    case 13:
      // changed max markup rate for greedy shopkeeps 3/15/98
      GET_INTEGER_ARG(ch, "Enter Owner's Markup: ", s->markup, -99, 999);
      break;

    case 14:
      GET_INTEGER_ARG(ch, "Enter # of Days Open (LOGGED): ", s->days_open, 0, 9999);
      break;

    case 15:
      GET_INTEGER_ARG(ch, "Enter Account Amount (LOGGED): ", s->gold, 0, 32767);
      break;

    default:
      send_to_char("That field cannot be changed.\n\r", ch);
      break;
  }
  ch->pc_specials->field_changed = TRUE;
}

ROA_MENU(plsedit_confirm_quit)
{
  char buf[MAX_STRING_LENGTH];
  char *p;

  if (!input_str)
  {
    MENU_PROMPT(ch) = "Quit editting plshop (yes/NO)? ";
    return;
  }

  strcpy(buf, input_str);
  p = strtok(buf, "   \n\r");
  if (p && strncasecmp("yes", p, strlen(p)) == 0)
    menu_jump(ch, plsedit_confirm_save);
  else
    menu_jump(ch, plsedit_top_menu);
}

ROA_MENU(plsedit_confirm_save)
{
  char buf[MAX_STRING_LENGTH];
  char *p;
  plshop *s = PLS_EDITTED(ch);

  if (!input_str)
  {
    MENU_PROMPT(ch) = "Save editted plshop to disk (YES/no)? ";
    return;
  }

  strcpy(buf, input_str);
  p = strtok(buf, "   \n\r");
  if (!p || strncasecmp("no", p, strlen(p)) != 0)
  {
    save_plshops();
    sprintf(buf, "PLRUPD: %s has editted plshop #%d", GET_NAME(ch), s->plshop_id);
    mudlog(buf, NRM, GET_LEVEL(ch), TRUE);
  }
  else
  if (IS_AIMP(ch))
  {
    menu_jump(ch, plsedit_confirm_delete);
    return;
  }

  PLS_EDITTED(ch) = NULL;
  MENU_PROMPT(ch)  = NULL;
  MENU_HANDLER(ch) = NULL;
  MENU_DEPTH(ch)   = 0;
  REMOVE_BIT(PLR_FLAGS(ch), PLR_BUILDING);
}

ROA_MENU(plsedit_confirm_delete)
{
  char fname[MAX_STRING_LENGTH];
  char *p;
  plshop *ptr = PLS_EDITTED(ch);

  if (!input_str)
  {
    MENU_PROMPT(ch) = "Delete plshop (yes/NO)? ";
    return;
  }

  strcpy(buf, input_str);
  p = strtok(buf, "   \n\r");
  if (p && strncasecmp("yes", p, strlen(p)) == 0)
  {
    send_to_char("Delete confirmed...\n\r",ch);

    // send log first, before we wax it
    sprintf(buf, "PLRUPD: %s has deleted plshop #%d", GET_NAME(ch), ptr->plshop_id);
    mudlog(buf, NRM, GET_LEVEL(ch), TRUE);

    // remove from disk
    sprintf(fname, "%s/%d.plshop", PLSHOP_DIR, ptr->plshop_id); 
    unlink(fname);

    // remove from memory
    remove_plshop_from_world(ptr);
    FREENULL(ptr);
  }
  else
    send_to_char("Delete not confirmed, plshop remains in global list.\n\r",ch);

  PLS_EDITTED(ch) = NULL;
  MENU_PROMPT(ch)  = NULL;
  MENU_HANDLER(ch) = NULL;
  MENU_DEPTH(ch)   = 0;
  REMOVE_BIT(PLR_FLAGS(ch), PLR_BUILDING);
}