/**************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* In order to use any part of this Merc Diku Mud, you must comply with *
* both the original Diku license in 'license.doc' as well the Merc *
* license in 'license.txt'. In particular, you may not remove either of *
* these copyright notices. *
* *
* Much time and thought has gone into this software and you are *
* benefiting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************
* ROM 2.4 is copyright 1993-1998 Russ Taylor *
* ROM has been brought to you by the ROM consortium *
* Russ Taylor (rtaylor@hypercube.org) *
* Gabrielle Taylor (gtaylor@hypercube.org) *
* Brian Moore (zump@rom.org) *
* By using this code, you have agreed to follow the terms of the *
* ROM license, in the file Rom24/doc/rom.license *
***************************************************************************
* 1stMUD ROM Derivative (c) 2001-2003 by Ryan Jennings *
* http://1stmud.dlmud.com/ <r-jenn@shaw.ca> *
***************************************************************************/
#include "merc.h"
#include "olc.h"
#include "magic.h"
#include "recycle.h"
AUCTION_DATA *auction_lookup(int num)
{
AUCTION_DATA *pAuc;
for (pAuc = auction_first; pAuc != NULL; pAuc = pAuc->next)
{
if (pAuc->number == num)
return pAuc;
}
return NULL;
}
int last_auc_id;
int get_auc_id(void)
{
last_auc_id++;
if (last_auc_id > 999)
last_auc_id = 1;
return last_auc_id;
}
CH_CMD(do_auction)
{
AUCTION_DATA *auc;
OBJ_DATA *obj = NULL;
long minbid = 1;
char arg1[MIL];
char arg2[MIL];
argument = first_arg(argument, arg1, FALSE);
argument = first_arg(argument, arg2, FALSE);
if (ch == NULL)
return;
if (IS_NULLSTR(arg1))
{
if (IS_SET(ch->info_settings, INFO_AUCTION))
{
REMOVE_BIT(ch->info_settings, INFO_AUCTION);
chprintln(ch, "{YAUCTION{x channel is now ON.");
}
else
{
SET_BIT(ch->info_settings, INFO_AUCTION);
chprintln(ch, "{YAUCTION{x channel is now OFF.");
}
return;
}
else if (!str_cmp(arg1, "talk"))
{
if (!IS_NPC(ch) && IS_SET(ch->info_settings, INFO_AUCTION))
{
chprintln
(ch, "Turn on the auction info channel first. (info auction)");
return;
}
if (IS_NULLSTR(arg2))
{
chprintln(ch, "You have nothing to say!");
return;
}
if (!IS_NULLSTR(argument))
{
strcat(arg2, " ");
strcat(arg2, argument);
}
announce(ch, INFO_AUCTION, "$n says: %s", arg2);
announce(ch, INFO_AUCTION | INFO_PRIVATE, "You say: %s", arg2);
return;
}
else if (!str_cmp(arg1, "stop") && IS_IMMORTAL(ch))
{
if (IS_NULLSTR(arg2) || !is_number(arg2))
{
chprintln(ch, "Stop which auction?");
return;
}
if ((auc = auction_lookup(atoi(arg2))) == NULL)
{
chprintln(ch, "No such auction.");
return;
}
if (auc->item)
{
announce(ch, INFO_AUCTION,
"$n has stopped the auction and confiscated %s!",
auc->item->short_descr);
announce(ch, INFO_AUCTION | INFO_PRIVATE,
"You have stopped the auction and confiscated %s!",
auc->item->short_descr);
obj_from_char(auc->item);
obj_to_char(auc->item, ch);
}
reset_auc(auc, TRUE);
return;
}
if ((obj = get_obj_carry(ch, arg1, ch)) == NULL)
{
chprintln(ch, "You aren't carrying that item.");
return;
}
if (IS_OBJ_STAT(obj, ITEM_AUCTIONED))
{
chprintln(ch, "That items is already being auctioned.");
return;
}
if (IS_OBJ_STAT(obj, ITEM_NODROP) && !IS_OBJ_STAT(obj, ITEM_QUEST))
{
chprintln(ch, "You can't let go of that item.");
return;
}
if (obj->item_type == ITEM_CORPSE_PC || obj->item_type == ITEM_CORPSE_NPC)
{
chprintln(ch, "Not a good idea....");
return;
}
if (count_auc(ch) >= 1)
{
chprintln(ch, "You are already auctioning something!");
return;
}
if (!IS_NULLSTR(arg2))
minbid = atol(arg2);
else if (IS_OBJ_STAT(obj, ITEM_QUEST))
minbid = qobj_cost(obj) / 3;
if (minbid > 500000 || minbid < 1)
{
chprintln(ch,
"Minumum bids can't be higher than 500000 or less than 1.");
return;
}
auc = new_auction();
LINK(auc, auction_first, auction_last, next, prev);
SET_BIT(obj->extra_flags, ITEM_AUCTIONED);
auc->owner = ch;
auc->item = obj;
auc->bid = minbid;
auc->number = get_auc_id();
auc->status = AUCTION_LENGTH;
announce(auc->owner, INFO_AUCTION,
"$n is auctioning %s (Level %d, Num %d). Current bid is %ld%s.",
auc->item->short_descr, auc->item->level, auc->number, auc->bid,
IS_OBJ_STAT(auc->item, ITEM_QUEST) ? "qp" : "g");
announce(auc->owner, INFO_AUCTION | INFO_PRIVATE,
"You are auctioning %s (Level %d, Num %d). Current bid is %ld%s.",
auc->item->short_descr, auc->item->level, auc->number, auc->bid,
IS_OBJ_STAT(auc->item, ITEM_QUEST) ? "qp" : "g");
return;
}
void auction_update(void)
{
AUCTION_DATA *auc, *auc_next;
for (auc = auction_first; auc != NULL; auc = auc_next)
{
auc_next = auc->next;
auc->status--;
if (auc->status < 0)
auc->status = 0;
if (!auc->item)
{
reset_auc(auc, TRUE);
bugf("Auction with no item, reseting.");
continue;
}
else if (auc->status % PULSE_PER_SECOND == 0)
{
switch (auc->status / PULSE_PER_SECOND)
{
case 0:
if (auc->high_bidder == NULL)
{
announce(NULL, INFO_AUCTION,
"No bids recieved on %s, sale stopped.",
auc->item->short_descr);
reset_auc(auc, TRUE);
}
else if ((unsigned long) (!IS_OBJ_STAT(auc->item, ITEM_QUEST)
? auc->high_bidder->gold : auc->
high_bidder->pcdata->questpoints) <
auc->bid)
{
announce(auc->high_bidder, INFO_AUCTION,
"$n can't cover their stake in the auction, sale stopped.");
announce(auc->high_bidder, INFO_AUCTION | INFO_PRIVATE,
"You can't cover your stake in the auction, sale stopped.");
reset_auc(auc, TRUE);
}
else
{
announce(auc->high_bidder, INFO_AUCTION,
"%s SOLD to $n for %ld %s.",
auc->item->short_descr, auc->bid,
IS_OBJ_STAT(auc->item,
ITEM_QUEST) ? "quest points" : "gold");
reset_auc(auc, FALSE);
}
break;
case 32:
announce(NULL, INFO_AUCTION,
"Going once %s (Level %d, Num %d). Current bid is %ld%s.",
auc->item->short_descr, auc->item->level,
auc->number, auc->bid, IS_OBJ_STAT(auc->item,
ITEM_QUEST) ?
"qp" : "g");
break;
case 15:
announce(NULL, INFO_AUCTION,
"Going twice %s (Level %d, Num %d). Current bid is %ld%s.",
auc->item->short_descr, auc->item->level,
auc->number, auc->bid, IS_OBJ_STAT(auc->item,
ITEM_QUEST) ?
"qp" : "g");
break;
}
}
}
return;
}
void reset_auc(AUCTION_DATA * auc, bool forced)
{
if (auc->item != NULL)
{
if (IS_OBJ_STAT(auc->item, ITEM_AUCTIONED))
REMOVE_BIT(auc->item->extra_flags, ITEM_AUCTIONED);
else
bug("item not flagged auction item");
if (!forced && auc->high_bidder != NULL && auc->bid > 0)
{
if (IS_OBJ_STAT(auc->item, ITEM_QUEST))
{
if (!IS_NPC(auc->owner) && !IS_NPC(auc->high_bidder))
{
auc->owner->pcdata->questpoints += auc->bid;
auc->high_bidder->pcdata->questpoints -= auc->bid;
}
}
else
{
auc->owner->gold += (auc->bid * 9) / 10;
deduct_cost(auc->high_bidder, auc->bid);
}
chprintlnf(auc->owner, "You recieve %ld %s for the sale of %s.",
!IS_OBJ_STAT(auc->item, ITEM_QUEST)
? (auc->bid * 9) /
10 : auc->bid,
!IS_OBJ_STAT(auc->item,
ITEM_QUEST) ? "gold" :
"quest points", auc->item->short_descr);
if (auc->item->carried_by)
obj_from_char(auc->item);
else if (auc->item->in_room)
obj_from_room(auc->item);
else if (auc->item->in_obj)
obj_from_obj(auc->item);
obj_to_char(auc->item, auc->high_bidder);
announce(auc->high_bidder, INFO_AUCTION | INFO_PRIVATE,
"You are sold %s for %ld %s.", auc->item->short_descr,
auc->bid,
!IS_OBJ_STAT(auc->item,
ITEM_QUEST) ? "gold" : "quest points");
}
else if (auc->owner != NULL)
chprintlnf(auc->owner, "Sale of %s has been stopped.",
auc->item->short_descr);
}
auc->bid = 0;
auc->high_bidder = NULL;
auc->item = NULL;
auc->owner = NULL;
auc->status = 0;
auc->number = 0;
UNLINK(auc, auction_first, auction_last, next, prev);
free_auction(auc);
return;
}
int count_auc(CHAR_DATA * ch)
{
AUCTION_DATA *q;
int count;
q = auction_first;
if (!q)
return 0;
for (count = 0; q; q = q->next)
{
if (q->owner == ch)
count++;
}
return count;
}
long advatoi(const char *s)
{
char string[MIL];
char *stringptr = string;
char tempstring[2];
long number = 0;
long multiplier = 0;
strcpy(string, s);
while (isdigit(*stringptr))
{
strncpy(tempstring, stringptr, 1);
number = (number * 10) + atol(tempstring);
stringptr++;
}
switch (UPPER(*stringptr))
{
case 'K':
multiplier = 1000;
number *= multiplier;
stringptr++;
break;
case 'M':
multiplier = 1000000;
number *= multiplier;
stringptr++;
break;
case '\0':
break;
default:
return 0;
}
while (isdigit(*stringptr) && (multiplier > 1))
{
strncpy(tempstring, stringptr, 1);
multiplier = multiplier / 10;
number = number + (atol(tempstring) * multiplier);
stringptr++;
}
if (*stringptr != '\0' && !isdigit(*stringptr))
return 0;
return (number);
}
unsigned long parsebet(const long currentbet, const char *argument)
{
long newbet = 0;
char string[MIL];
char *stringptr = string;
strcpy(string, argument);
if (*stringptr)
{
if (isdigit(*stringptr))
newbet = advatoi(stringptr);
else if (*stringptr == '+')
{
if (strlen(stringptr) == 1)
newbet = (currentbet * 125) / 100;
else
newbet = (currentbet * (100 + atoi(++stringptr))) / 100;
}
else
{
printf("considering: * x \n\r");
if ((*stringptr == '*') || (*stringptr == 'x'))
{
if (strlen(stringptr) == 1)
newbet = currentbet * 2;
else
newbet = currentbet * atoi(++stringptr);
}
}
}
return newbet;
}
CH_CMD(do_bid)
{
char arg1[MIL];
char arg2[MIL];
AUCTION_DATA *auc, *auc_next;
argument = one_argument(argument, arg1);
argument = one_argument(argument, arg2);
if (auction_first == NULL)
{
chprintln(ch, "There's nothing up for auction right now.");
return;
}
if (IS_NULLSTR(arg1))
{
chprintlnf(ch,
" {Y[ Auction - Current List of Inventory ]{x");
chprintln(ch,
"{GNum Seller Item Description Lvl Last Bid Time{x");
chprintln(ch,
"{W--- ------------ ----------------------------------- --- ------------- ------------{x");
for (auc = auction_first; auc; auc = auc_next)
{
auc_next = auc->next;
if (!auc->item)
{
reset_auc(auc, TRUE);
continue;
}
if (!IS_OBJ_STAT(auc->item, ITEM_AUCTIONED))
bug("Auctioned item is not flaged Auctioned.");
chprintlnf(ch, "{R%3d{x - %-12s " MXPTAG("Bid %d") "%34s"
MXPTAG("/Bid") " %3d {R%11ld%-2s{G %s{x",
auc->number, auc->owner->name, auc->number,
stringf(ch, 34, ALIGN_LEFT, NULL,
auc->item->short_descr), auc->item->level,
auc->bid, IS_OBJ_STAT(auc->item,
ITEM_QUEST) ? "qp" : "g ",
format_pulse(auc->status));
}
chprintln(ch,
"{W------------------------------------------------------------------------------------{x");
chprintln(ch,
"Type: 'Bid <num>' to see stats and 'Bid <num> <amount>' to bid on an item.");
return;
}
else if ((auc = auction_lookup(atoi(arg1))) != NULL)
{
if (!auc->item)
{
reset_auc(auc, TRUE);
chprintln(ch, "No such item.");
return;
}
if (IS_NULLSTR(arg2))
{
if (ch == auc->owner && !IS_IMMORTAL(ch))
{
chprintlnf(ch, "You're auctioning %s.", auc->item->short_descr);
chprintlnf(ch, "Current bid is %ld %s.",
auc->bid,
IS_OBJ_STAT(auc->item,
ITEM_QUEST) ? "quest points" : "gold");
return;
}
spell_identify(0, ch->level, ch, auc->item, TAR_OBJ_INV);
chprintf(ch, "Current bid is %ld %s", auc->bid,
IS_OBJ_STAT(auc->item,
ITEM_QUEST) ? "quest points" : "gold");
if (auc->high_bidder)
chprintlnf(ch, ", placed by %s.", PERS(auc->high_bidder, ch));
else
chprintln(ch, ".");
if (IS_OBJ_STAT(auc->item, ITEM_QUEST))
chprintln
(ch,
"Some affects will change with your level once the item is in your possession.");
return;
}
else
{
unsigned long bid = 0;
if (ch == auc->high_bidder)
{
chprintln(ch, "You already have the highest bid!");
return;
}
if (ch == auc->owner)
{
chprintln(ch, "You cannot bid on your own items!");
return;
}
bid = parsebet(auction_first->bid, arg2);
if (bid < 0 || bid > 200000000)
{
chprintln(ch, "Invalid bid.");
return;
}
if (!IS_OBJ_STAT(auc->item, ITEM_QUEST))
{
if ((unsigned long) ch->gold < bid)
{
chprintln(ch, "You can't cover that bid.");
return;
}
}
else
{
if (ch->pcdata->questpoints < (int) bid)
{
chprintln(ch, "You can't cover that bid.");
return;
}
}
if (bid < auc->bid)
{
chprintlnf(ch, "The minimum bid is %ld %s.",
auc->bid,
IS_OBJ_STAT(auc->item,
ITEM_QUEST) ? "quest points" : "gold");
return;
}
if (bid < (auc->bid + 10))
{
chprintlnf(ch, "You must outbid %ld %s by at least 10.",
auc->bid,
IS_OBJ_STAT(auc->item,
ITEM_QUEST) ? "quest points" : "gold");
return;
}
announce(NULL, INFO_AUCTION, "%ld %s has been offered for %s.",
bid, IS_OBJ_STAT(auc->item,
ITEM_QUEST) ? "quest points" : "gold",
auc->item->short_descr);
chprintlnf(ch, "You offer %ld %s for %s.",
bid, IS_OBJ_STAT(auc->item,
ITEM_QUEST) ? "quest points" : "gold",
auc->item->short_descr);
auc->high_bidder = ch;
auc->bid = bid;
auc->status = AUCTION_LENGTH;
return;
}
}
else
chprintln
(ch, "Bid on what object? (type 'bid', nothing else for a list)");
}
bool has_auction(CHAR_DATA * ch)
{
AUCTION_DATA *auc;
for (auc = auction_first; auc != NULL; auc = auc->next)
{
if (auc->owner == ch || auc->high_bidder == ch)
return TRUE;
}
return FALSE;
}
void extract_auc(CHAR_DATA * ch)
{
AUCTION_DATA *auc, *auc_next;
for (auc = auction_first; auc != NULL; auc = auc_next)
{
auc_next = auc->next;
if (auc->owner == ch)
{
reset_auc(auc, TRUE);
continue;
}
if (auc->high_bidder == ch)
{
reset_auc(auc, TRUE);
continue;
}
}
}