/****************************************************************************
* [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame | *
* -----------------------------------------------------------| \\._.// *
* SmaugWiz (C) 1998 by Russ Pillsbury (Windows NT version) | (0...0) *
* -----------------------------------------------------------| ).:.( *
* SMAUG (C) 1994, 1995, 1996 by Derek Snider | {o o} *
* -----------------------------------------------------------| / ' ' \ *
* SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus, |~'~.VxvxV.~'~*
* Scryn, Swordbearer, Rennard, Tricops, and Gorog. | *
* ------------------------------------------------------------------------ *
* Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik Staerfeldt, Tom Madsen, and Katja Nyboe. *
****************************************************************************/
// Auction.cpp
#include "stdafx.h"
#include "smaug.h"
#include "sysdata.h"
#include "area.h"
#include "objects.h"
#include "rooms.h"
#include "skill.h"
#include "auction.h"
#include "bet.h"
#include "character.h"
// put an item on auction, or see the stats on the current item or bid
void do_auction (CCharacter *ch, char *argument)
{
CObjData *obj;
char arg1 [MAX_INPUT_LENGTH];
char arg2 [MAX_INPUT_LENGTH];
char buf [MAX_STRING_LENGTH];
argument = one_argument (argument, arg1);
// NPC can be extracted at any time and thus can't auction!
if (ch->IsNpc ())
return;
if ((time_info.hour > 18 || time_info.hour < 9) && ! auction->IsActive ()) {
set_char_color (AT_LBLUE, ch);
ch->SendText ("\n\rThe auctioneer has retired for the evening...\n\r");
return;
}
if (arg1 [0] == '\0') {
if (auction->IsActive ()) {
obj = auction->GetItem ();
// show item data here
if (auction->GetBid () > 0)
sprintf (buf, "Current bid on this item is %d gold.\n\r",
auction->GetBid ());
else
sprintf (buf, "No bids on this item have been received.\n\r");
set_char_color (AT_BLUE, ch);
ch->SendText (buf);
sprintf (buf,
"Object '%s' is %s, special properties:%s%s%s.\n\r"
"Its weight is %d, value is %d, and level is %d.\n\r",
obj->GetName (), aoran (item_type_name (obj)),
NCCP obj->AntiClassNames (),
ExtraBitName (obj->m_ExtraFlags),
magic_bit_name (obj->magic_flags),
obj->weight, obj->cost, obj->level);
set_char_color (AT_LBLUE, ch);
ch->SendText (buf);
sprintf (buf, "Worn on: %s\n\r",
flag_string (obj->wear_flags -1, w_flags));
ch->SendText (buf);
set_char_color (AT_BLUE, ch);
switch (obj->item_type) {
case ITEM_PILL:
case ITEM_SCROLL:
case ITEM_POTION:
sprintf (buf, "Level %d spells of:", obj->value [0]);
ch->SendText (buf);
if (obj->value [1] >= 0
&& obj->value [1] < SkillTable.GetCount ()) {
ch->SendText (" '");
ch->SendText (SkillTable.GetName (obj->value [1]));
ch->SendText ("'");
}
if (obj->value [2] >= 0
&& obj->value [2] < SkillTable.GetCount ()) {
ch->SendText (" '");
ch->SendText (SkillTable.GetName (obj->value [2]));
ch->SendText ("'");
}
if (obj->value [3] >= 0
&& obj->value [3] < SkillTable.GetCount ()) {
ch->SendText (" '");
ch->SendText (SkillTable.GetName (obj->value [3]));
ch->SendText ("'");
}
ch->SendText (".\n\r");
break;
case ITEM_WAND:
case ITEM_STAFF:
sprintf (buf, "Has %d (%d) charges of level %d",
obj->value [1], obj->value [2], obj->value [0]);
ch->SendText (buf);
if (obj->value [3] >= 0
&& obj->value [3] < SkillTable.GetCount ()) {
ch->SendText (" '");
ch->SendText (SkillTable.GetName (obj->value [3]));
ch->SendText ("'");
}
ch->SendText (".\n\r");
break;
case ITEM_WEAPON:
sprintf (buf, "Damage is %d to %d (average %d).\n\r",
obj->value [1], obj->value [2],
(obj->value [1] + obj->value [2]) / 2);
ch->SendText (buf);
break;
case ITEM_ARMOR:
sprintf (buf, "Armor class is %d.\n\r", obj->value [0]);
ch->SendText (buf);
break;
}
CAffectList &IList = obj->pIndexData->AffList;
POSITION apos = IList.GetHeadPosition ();
while (apos)
IList.GetNext (apos)->ShowAffect (ch);
CAffectList &AList = obj->AffList;
apos = AList.GetHeadPosition ();
while (apos)
AList.GetNext (apos)->ShowAffect (ch);
if (obj->item_type == ITEM_CONTAINER && ! obj->IsEmpty ()) {
set_char_color (AT_OBJECT, ch);
ch->SendText ("Contents:\n\r");
ShowListToChar (obj->GetContentList (), ch, TRUE, FALSE);
}
if (ch->IsImmortal ()) {
sprintf (buf, "Seller: %s. Bidder: %s. Round: %d.\n\r",
auction->GetSeller ()->GetName (),
auction->GetBuyer ()->GetName (),
(auction->GetCount () + 1));
ch->SendText (buf);
sprintf (buf, "Time left in round: %d.\n\r",
auction->GetPulse ());
ch->SendText (buf);
}
return;
} else {
set_char_color (AT_LBLUE, ch);
ch->SendText ("\n\rThere is nothing being auctioned right now. "
"What would you like to auction?\n\r");
return;
}
}
CCharacter &Seller = *auction->GetSeller ();
CCharacter &Buyer = *auction->GetBuyer ();
if (ch->IsImmortal () && !str_cmp (arg1, "stop"))
if (! auction->IsActive ()) {
ch->SendText ("There is no auction to stop.\n\r");
return;
} else { // stop the auction
set_char_color (AT_LBLUE, ch);
sprintf (buf, "Sale of %s has been stopped by an Immortal.",
auction->GetItem ()->GetShortDescr ());
talk_auction (buf);
obj_to_char (auction->GetItem (), &Seller);
if (SysData.IsSaveOnAuction ())
save_char_obj (&Seller);
auction->Stop ();
return;
}
if (!str_cmp (arg1, "bid"))
if (auction->IsActive ()) {
int newbet;
if (ch == &Seller) {
ch->SendText ("You can't bid on your own item!\n\r");
return;
}
// make - perhaps - a bid now
if (argument [0] == '\0') {
ch->SendText ("Bid how much?\n\r");
return;
}
newbet = parsebet (auction->GetBid (), argument);
//ch_printf (ch, "Bid: %d\n\r", newbet);
if (newbet < auction->GetStartPrice ()) {
ch->SendText ("You must place a bid that is higher than "
"the starting price.\n\r");
return;
}
// to avoid slow auction, use a bigger amount than 100
// if the bet is higher up.
// changed to 10000 for our high economy.
if (newbet < (auction->GetBid () + 10000)) {
ch->SendText ("You must at least bid 10000 coins over "
"the current bid.\n\r");
return;
}
if (newbet > ch->GetGold ()) {
ch->SendText ("You don't have that much money!\n\r");
return;
}
if (newbet > 2000000000) {
ch->SendText ("You can't bid over 2 billion coins.\n\r");
return;
}
// the actual bet is OK!
// return the gold to the last buyer, if one exists
if (auction->IsBuyer () && &Buyer != &Seller)
Buyer.AddGold (auction->GetBid ());
ch->AddGold (-newbet); // subtract the gold - important :)
if (SysData.IsSaveOnAuction ())
save_char_obj (ch);
auction->Reset (ch, newbet); // start the auction over again
sprintf (buf, "A bid of %d gold has been received on %s.\n\r",
newbet, auction->GetItem ()->GetShortDescr ());
talk_auction (buf);
return;
} else {
ch->SendText ("There isn't anything being auctioned right now.\n\r");
return;
}
// finally...
if (ms_find_obj (ch))
return;
obj = get_obj_carry (ch, arg1); // does char have the item ?
if (obj == NULL) {
ch->SendText ("You aren't carrying that.\n\r");
return;
}
if (obj->timer > 0) {
ch->SendText ("You can't auction objects that are decaying.\n\r");
return;
}
argument = one_argument (argument, arg2);
if (arg2 [0] == '\0') {
auction->SetStartPrice (0);
strcpy (arg2, "0");
}
if (!is_number (arg2)) {
ch->SendText ("You must input a number at which to start the "
"auction.\n\r");
return;
}
if (atoi (arg2) < 0) {
ch->SendText ("You can't auction something for less than 0 gold!\n\r");
return;
}
if (! auction->IsActive ())
switch (obj->item_type) {
default:
act (AT_TELL, "You cannot auction $Ts.", ch, NULL,
item_type_name (obj), TO_CHAR);
return;
// insert any more item types here...
// items with a timer MAY NOT BE AUCTIONED!
case ITEM_LIGHT:
case ITEM_TREASURE:
case ITEM_POTION:
case ITEM_CONTAINER:
case ITEM_DRINK_CON:
case ITEM_FOOD:
case ITEM_PEN:
case ITEM_BOAT:
case ITEM_PILL:
case ITEM_PIPE:
case ITEM_HERB_CON:
case ITEM_INCENSE:
case ITEM_FIRE:
case ITEM_RUNEPOUCH:
case ITEM_MAP:
case ITEM_BOOK:
case ITEM_RUNE:
case ITEM_MATCH:
case ITEM_HERB:
case ITEM_WEAPON:
case ITEM_ARMOR:
case ITEM_STAFF:
case ITEM_WAND:
case ITEM_SCROLL:
separate_obj (obj);
obj_from_char (obj);
if (SysData.IsSaveOnAuction ())
save_char_obj (ch);
auction->SetItem (obj);
auction->SetSeller (ch);
auction->Reset (ch, 0);
int Start = atoi (arg2);
auction->SetStartPrice (Start);
if (Start > 0)
auction->SetBid (Start);
sprintf (buf, "A new item is being auctioned: %s at %d gold.",
obj->GetShortDescr (), Start);
talk_auction (buf);
return;
} // switch
else {
act (AT_TELL,
"Try again later - $p is being auctioned right now!",
ch, auction->GetItem (), NULL, TO_CHAR);
WAIT_STATE (ch, (short) (1.5 * PULSE_VIOLENCE));
return;
}
}
// the auction update
void CAuctionData::Update ()
{
int tax, pay;
char buf [MAX_STRING_LENGTH];
if (! m_pItem) then return;
if (--m_Pulse > 0) then return;
m_Pulse = PULSE_AUCTION;
switch (++m_Going) { // increase the going state
case 1 : // going once
case 2 : // going twice
if (m_Bid > m_Start)
sprintf (buf, "%s: going %s for %d.", m_pItem->GetShortDescr (),
((m_Going == 1) ? "once" : "twice"), m_Bid);
else
sprintf (buf, "%s: going %s (bid not received yet).",
m_pItem->GetShortDescr (), ((m_Going == 1) ? "once" : "twice"));
talk_auction (buf);
break;
case 3 : /* SOLD! */
if (! m_pBuyer && m_Bid) {
bug ("Auction code reached SOLD, with NULL buyer, but %d gold "
"bid", m_Bid);
m_Bid = 0;
}
if (m_Bid > 0 && m_pBuyer != m_pSeller) {
sprintf (buf, "%s sold to %s for %d.", m_pItem->GetShortDescr (),
m_pBuyer->IsNpc () ? m_pBuyer->GetShortDescr () :
m_pBuyer->GetName (), m_Bid);
talk_auction (buf);
act (AT_ACTION, "The auctioneer materializes before you, and "
"hands you $p.", m_pBuyer, m_pItem, NULL, TO_CHAR);
act (AT_ACTION, "The auctioneer materializes before $n, and "
"hands $m $p.", m_pBuyer, m_pItem, NULL, TO_ROOM);
if ((m_pBuyer->GetCarryWeight () + get_obj_weight (m_pItem))
> can_carry_w (m_pBuyer)) {
act (AT_PLAIN, "$p is too heavy for you to carry with your "
"current inventory.", m_pBuyer, m_pItem, NULL, TO_CHAR);
act (AT_PLAIN, "$n is carrying too much to also carry $p, "
"and $e drops it.", m_pBuyer, m_pItem, NULL, TO_ROOM);
obj_to_room (m_pItem, m_pBuyer->GetInRoom ());
}
else
obj_to_char (m_pItem, m_pBuyer);
pay = (int) (m_Bid * 0.9);
tax = (int) (m_Bid * 0.1);
m_pSeller->GetInRoom ()->GetArea ()->BoostEconomy (tax);
m_pSeller->AddGold (pay); // give him the money, tax 10 %
sprintf (buf, "The auctioneer pays you %d gold, charging an "
"auction fee of %d.\n\r", pay, tax);
m_pSeller->SendText (buf);
m_pItem = NULL; // reset item
if (SysData.IsSaveOnAuction ()) {
save_char_obj (m_pBuyer);
save_char_obj (m_pSeller);
}
} else { // not sold
sprintf (buf, "No bids received for %s - object has been "
"removed from auction\n\r.", m_pItem->GetShortDescr ());
talk_auction (buf);
act (AT_ACTION, "The auctioneer appears before you to "
"return $p to you.", m_pSeller, m_pItem, NULL, TO_CHAR);
act (AT_ACTION, "The auctioneer appears before $n to "
"return $p to $m.", m_pSeller, m_pItem, NULL, TO_ROOM);
if ((m_pSeller->GetCarryWeight () + get_obj_weight (m_pItem))
> can_carry_w (m_pSeller)) {
act (AT_PLAIN, "You drop $p as it is just too much to carry"
" with everything else you're carrying.", m_pSeller,
m_pItem, NULL, TO_CHAR);
act (AT_PLAIN, "$n drops $p as it is too much extra weight"
" for $m with everything else.", m_pSeller,
m_pItem, NULL, TO_ROOM);
obj_to_room (m_pItem, m_pSeller->GetInRoom ());
}
else
obj_to_char (m_pItem, m_pSeller);
tax = (int) (m_pItem->cost * 0.05);
m_pSeller->GetInRoom ()->GetArea ()->BoostEconomy (tax);
sprintf (buf, "The auctioneer charges you an auction fee of "
"%d.\n\r", tax);
m_pSeller->SendText (buf);
if ((m_pSeller->GetGold () - tax) < 0)
m_pSeller->SetGold (0);
else
m_pSeller->AddGold (-tax);
if (SysData.IsSaveOnAuction ())
save_char_obj (m_pSeller);
} // else
m_pItem = NULL; // clear auction
} // switch
}
void CAuctionData::Stop ()
{
if (IsBuyer () && m_pBuyer != m_pSeller) {
m_pBuyer->AddGold (m_Bid);
m_pBuyer->SendText ("Your money has been returned.\n\r");
}
m_pItem = NULL;
}