/**************************************************************************** * [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; }