/
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

auction.c				Commands, utilities dealing with
					automated auctioning system...

		******** Heavily modified and expanded ********
		******** 100% Completely Original Code ********
		*** BE AWARE OF ALL RIGHTS AND RESERVATIONS ***
		******** Heavily modified and expanded ********
		******** 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 "interpreter.h"
#include "acmd.h"
#include "handler.h"
#include "db.h"
#include "magic.h"
#include "lists.h"
#include "global.h"
#include "darkenelf.h"

// external functions
extern void send_auction(char *messg);
extern chdata *get_char_by_id(long id);
extern void clear_and_remove_auction(aucdata *aptr);

// 10/10/97, jtrhone, now can have multiple auctions... linked list of auctions...
BOOL auction_in_progress(void)
{
  if (auction_ptr) return TRUE;
  else return FALSE;
}

aucdata *get_auction_ptr(int anum)
{
  aucdata *aptr = auction_ptr;

  for ( ; aptr; aptr=aptr->next)
    if (aptr->id == anum)
      return aptr;

  return NULL;
}

int num_auctions(void)
{
  aucdata *aptr = auction_ptr;
  int num;

  for(num = 0; aptr; aptr=aptr->next)
    num++;

  return num;
}

// insert auction into end of linked list of auctions (keep sane order) -roa
void insert_auction(aucdata *aptr)
{
  aucdata *tmp;

  if (!auction_ptr)
    auction_ptr = aptr;
  else
  {
    for (tmp = auction_ptr; tmp && tmp->next; tmp=tmp->next)
      ;
    tmp->next = aptr;
  }
}

ACMD(do_auction)
{
  char  arg1[MAX_INPUT_LENGTH];
  char  arg2[MAX_INPUT_LENGTH];
  obdata *obj;
  int price;
  aucdata *aptr;

  half_chop(argument, arg1, arg2);

  if (IS_NPC(ch))
     return;

  if (PRF_FLAGGED(ch, PRF_NOAUCT))
  {
    send_to_char("You aren't even listening to the auction channel!\n\r", ch);
    return;
  }

  if (!*arg1)
  {
    send_to_char("What do you want to auction?\n\r", ch);
    return;
  }

  if (!*arg2)
  {
    send_to_char("What price do you want to auction it for?\n\r", ch);
    return;
  }

  if (is_number(arg2))
    price = atoi(arg2);
  else
  {
     send_to_char("The price must be a number.\n\r",ch);
     return;
  }

  if (price < 1)
  {
      send_to_char("The price must be a POSITIVE number.\n\r",ch);
      return;
  } else if (price > 5000000) // Get around bidid loop 08/22/98 -callahan
    price = 5000000;

  if (!ch->carrying)
  {
      send_to_char("You don't seem to have anything to auction!\n\r", ch);
      return;
  }

  if (!(obj = get_obj_in_list_vis(ch, arg1, ch->carrying)))
  {
      sprintf(buf, "You aren't carrying %s in your inventory.\n\r",arg1);
      S2C();
      return;
  }

  if (IS_CORPSE(obj) || (obj->cost < 100) || (price < 100) || OBJ_FLAGGED2(obj, ITEM_NOAUCTION))
  {
     send_to_char("You cannot auction that item.\n\r",ch);
     return;
  }

  if (IS_IMMORTAL(ch) && GET_LEVEL(ch) < LEV_IMPL)
  {
    send_to_char("Immortals may not participate in an auction.\n\r",ch);
    return;
  }

  /* passed all the checks now we begin the auction */

  // alloc the memory
  CREATE(aptr, aucdata, 1);
  if (global_auc_id++ >= 1000)
    global_auc_id = 1;
  aptr->id = global_auc_id;

  sprintf(buf, "You begin to auction %s asking %d %s.\n\r", obj->shdesc, price, currency_name_plural);
  S2C();
  sprintf(buf, "%%B[Auction]%%0 %s begins auctioning %s for %%6%%B%d%%0 %s (%%B#%d%%0).\n\r",
          GET_NAME(ch), obj->shdesc, price, currency_name_plural, aptr->id);
  send_auction(buf);

  aptr->item_auc = obj;
  obj_from_char(obj);
  save_char(ch, NOWHERE);

  aptr->bid_on = FALSE;
  aptr->seller_id_num = GET_IDNUM(ch);
  aptr->last_bid = 0;
  aptr->bidder_id_num = 0;
  aptr->selling_price = price;
  aptr->state_of_sale = 0;

  insert_auction(aptr);
}

void show_auctions(chdata *ch)
{
  obdata *obj;
  aucdata *aptr = auction_ptr;
  int next;

  sprintf(buf, "%%BCurrent auctions:%%0\n\r%%B-----------------%%0\n\r");
  for (; aptr; aptr=aptr->next)
  {
    next = (int)(aptr->selling_price * 0.05);
    obj = aptr->item_auc;
    sprintf(buf+strlen(buf), "(%3d) %-35.35s : %%B%d%%0 %s, level %d \n\r", aptr->id, obj->shdesc,
            MAX((aptr->last_bid+next), aptr->selling_price), currency_name_plural, obj->min_level);
  }

  if (auction_ptr)
    page_string(ch->desc, buf, 1);
  else
  {
    str_cat(buf, "None.\n\r", MAX_STRING_LENGTH, "show_auctions");
    S2C();
  }
}

ACMD(do_bid)
{
  obdata *obj;
  int bid, next;
  chdata *prv_bidder = NULL;
  char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH];
  int anum = -1;
  aucdata *aptr = NULL;

  if (IS_NPC(ch))
     return;

  if (IS_IMMORTAL(ch) && GET_LEVEL(ch) < LEV_IMPL)
  {
    send_to_char("Immortals may not participate in an auction.\n\r",ch);
    return;
  }

  if (PRF_FLAGGED(ch, PRF_NOAUCT))
  {
   send_to_char("You aren't even listening to the auction channel!\n\r", ch);
   return;
  }

  if (!auction_in_progress())
  {
   send_to_char("There is no auction going on at the moment!\n\r", ch);
   return;
  }

  // determine which item player is bidding on
  half_chop(argument, arg1, arg2);

  /* RoA ...removed free identify */
  if (!*arg1)
  {
    show_auctions(ch);
    return;
  }

  if (!*arg2 || !is_number(arg2))
  {
    send_to_char("Usage: bid <amount> <auction #>\n\r",ch);
    return;
  }

  anum = atoi(arg2);
  if (!(aptr = get_auction_ptr(anum)))
  {
    send_to_char("Invalid auction number.\n\r",ch);
    show_auctions(ch);
    return;
  }

  /* bid in increments of original asking price RoA 5 percent for now */
  next = (int)(aptr->selling_price * 0.05);

  if (GET_IDNUM(ch) == aptr->seller_id_num)
  {
     send_to_char("You can't bid, you're auctioning the item.\n\r",ch);
     return;
  }

  if (GET_IDNUM(ch) == aptr->bidder_id_num)
  {
     send_to_char("You already have the last bid.\n\r",ch);
     return;
  }

  /* Get the bid off the person */

  if (is_number(arg1))
      bid = atoi(arg1);
  else
  {
     send_to_char("The bid must be a number.\n\r",ch);
     return;
  }

  if (bid < 1)
  {
    sprintf(buf, "The bid must be at least one %s!\n\r", currency_name);
    S2C();
    return;
  }

  if (bid < aptr->selling_price)
  {
      send_to_char("You can't bid below the asking price!\n\r",ch);
      return;
  }

  if (bid < (aptr->last_bid + next))
  {
      send_to_char("You must bid higher than that.\n\r", ch);
      return;
  }

  if (bid > GET_GOLD(ch))
  {
      send_to_char("You dont have that much on hand!!\n\r",ch);
      return;
  }
  GET_GOLD(ch) -= bid;

  /* ok, we have a new bid, so go thru and give the money back to whoever
     bid last -roa */
  if (aptr->last_bid > 0 && aptr->bidder_id_num)
    if ((prv_bidder = get_char_by_id(aptr->bidder_id_num)))
    {
      GET_GOLD(prv_bidder) += aptr->last_bid;

      sprintf(buf, "Your %s have been returned to you.", currency_name_plural);
      act(buf, FALSE, prv_bidder, 0, 0, TO_CHAR);
    }

  obj = aptr->item_auc;
  sprintf(buf, "You bid %d %s for %s (#%d).\n\r", bid, currency_name_plural,
          obj->shdesc, aptr->id);
  S2C();

  sprintf(buf, "%%B[Auction]%%0 %s bids %%6%%B%d%%0 %s on %s (#%d).\n\r",
          GET_NAME(ch), bid, currency_name_plural, obj->shdesc, aptr->id);
  send_auction(buf);

  aptr->bid_on = TRUE;
  aptr->bidder_id_num = GET_IDNUM(ch);
  aptr->last_bid = bid;
  aptr->state_of_sale = 1;
}

// RoA, added an identify for money, bidid
ACMD(do_bidid)
{
  obdata *obj;
  aucdata *aptr;
  int next, anum;

  if (IS_NPC(ch))
     return;

  if (PRF_FLAGGED(ch, PRF_NOAUCT))
  {
   send_to_char("You aren't even listening to the auction channel!\n\r", ch);
   return;
  }

  if (!auction_ptr)
  {
   send_to_char("There is no auction going on at the moment!\n\r", ch);
   return;
  }

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

  anum = atoi(arg);
  if (!(aptr = get_auction_ptr(anum)))
  {
    send_to_char("Invalid auction number.\n\r",ch);
    show_auctions(ch);
    return;
  }

  if (GET_IDNUM(ch) == aptr->seller_id_num)
  {
    send_to_char("You may not bidid an item you are auctioning.\n\r",ch);
    return;
  }

  if (!(obj = aptr->item_auc))
  {
    send_to_char("Auction fatal error #1.  Please report to an immortal asap.\n\r",ch);
    return;
  }

  // make sure have money
  if (GET_GOLD(ch) < 500 && !IS_IMMORTAL(ch))
  {
    sprintf(buf, "Bidid costs 500 %s, which you don't have.\n\r", currency_name_plural);
    S2C();
    return;
  }
  if (!IS_IMMORTAL(ch))
    GET_GOLD(ch) -= 500;

  send_to_char("%B%6Auction Identification%0\n\r",ch);

  // have them cast the spell
  (*spell_info[SPELL_IDENTIFY].spell_pointer) (ch, "", NULL, obj);

  if (GET_IDNUM(ch) == aptr->seller_id_num)
     send_to_char("You are auctioning the item.\n\r",ch);
  else
  {
    if (GET_IDNUM(ch) && GET_IDNUM(ch) == aptr->bidder_id_num)
    {
       sprintf(buf, "You have the last bid at %%5%ld%%0 %s.\n\r", aptr->last_bid, currency_name_plural);
       S2C();
    }
    else
    {
      next = (int)(aptr->selling_price * 0.05);
      sprintf(buf, "Next possible bid on %s (#%d): %%B%d%%0 %s.\n\r",
              obj->shdesc, aptr->id, MAX((aptr->last_bid+next), aptr->selling_price),
              currency_name_plural);
      S2C();
    }
  }
}

void update_single_auction(aucdata *aptr)
{
  chdata *target;
  obdata *obj;
  static struct show_struct {
      char      *cmd;
  } fields[] = {
      { "test" },
      { "Going once" },
      { "Going twice" },
      { "Going three times" },
      { "Sold!" },
      { "\n" }
  };

  obj = aptr->item_auc;
  if (aptr->bid_on)
  {
    /* check to see if bidder is still here */
    if (!aptr->bidder_id_num || !(target = get_char_by_id(aptr->bidder_id_num)))
    {
     sprintf(buf, "%%B[Auction]%%0 Auction %%B#%d%%0 cancelled because the highest bidder left!\n\r",
             aptr->id);
     send_auction(buf);

     /* give obj back to seller if he/she is here */
     if ((target = get_char_by_id(aptr->seller_id_num)))
      obj_to_char(obj, target);

     clear_and_remove_auction(aptr);
     return;
    }
  }

  /* check to see if seller is gone */
  if (!(target = get_char_by_id(aptr->seller_id_num)))
  {
    sprintf(buf, "%%B[Auction]%%0 Auction %%B#%d%%0 cancelled because the seller left!\n\r", aptr->id);
    send_auction(buf);

    /* ok, if we HAD a bid, go thru and give the money back to whoever bid*/
    if (aptr->bid_on && aptr->bidder_id_num)
    if ((target = get_char_by_id(aptr->bidder_id_num)))
    {
      GET_GOLD(target) += aptr->last_bid;

      sprintf(buf, "Your %s have been returned to you.", currency_name_plural);
      act(buf, FALSE, target, 0,0, TO_CHAR);
    }

    clear_and_remove_auction(aptr);
    return;
  }

  if ((!aptr->state_of_sale) && (!aptr->bid_on))
  {
    sprintf(buf, "%%B[Auction]%%0 Auction %%B#%d%%0 cancelled due to lack of interest on %s!\n\r",
              aptr->id, obj->shdesc);
    send_auction(buf);

    /* search for the seller and give back item */
    if ((target = get_char_by_id(aptr->seller_id_num)))
    {
     obj_to_char(obj, target);
     save_char(target, NOWHERE);
    }

    clear_and_remove_auction(aptr);
    return;
  }

  if (aptr->state_of_sale)
  {
    sprintf(buf, "%%B[Auction]%%0 %%B#%d%%0 %s for %ld %s! (%s)\n\r", aptr->id,
            fields[aptr->state_of_sale].cmd, aptr->last_bid, currency_name_plural,
            obj->shdesc);
    send_auction(buf);

    if (aptr->state_of_sale < 4)
      aptr->state_of_sale++;
    else
    {
        /* search for the seller and give money */
        if ((target = get_char_by_id(aptr->seller_id_num)))
        {
          GET_GOLD(target) = (GET_GOLD(target) + aptr->last_bid);
          save_char(target, NOWHERE);
          sprintf(buf, "You receive %ld %s for %s from auction %%B#%d%%0.\n\r",
                  aptr->last_bid, currency_name_plural, obj->shdesc, aptr->id);
          send_to_char(buf, target);
        }

        /* search for the bidder and give item */
        if ((target = get_char_by_id(aptr->bidder_id_num)))
        {
          obj_to_char(obj,target);
          save_char(target, NOWHERE);
          sprintf(buf, "You bought %s for %ld %s from auction %%B#%d%%0.\n\r", obj->shdesc,
                  aptr->last_bid, currency_name_plural, aptr->id);
          send_to_char(buf,target);
          clear_and_remove_auction(aptr);
        }
    }
  }  // state of sale...
}

// now multiple auctions... -roa 10/10/97
void do_auction_update ( void )
{
  aucdata *aptr, *next_aptr;

  for (aptr = auction_ptr; aptr; aptr = next_aptr)
  {
    next_aptr = aptr->next;
    update_single_auction(aptr);
  }
}