/************************************************************************** * 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 * *************************************************************************** * _/_/_/ _/ _/ _/ Devil's Lament MUD * * _/ _/ _/ _/ _/ _/ (c) 1999-2002 by Ryan Jennings * * _/ _/ _/ _/ _/ Telnet : <dlmud.com:3778> * * _/_/_/ _/_/_/ _/ _/ E-Mail : <dlmud@dlmud.com> * * Website: <http://www.dlmud.com/> * ***************************************************************************/ #include <sys/types.h> #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #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); bug("Auction with no item, reseting.", 0); continue; } else { switch (auc->status) { 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 PULSE_PER_SECOND * 30: 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 PULSE_PER_SECOND * 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", 0); 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.", 0); chprintlnf(ch, "{R%3d{x - %-12s %34s %3d {R%11ld%-2s{G %4d{x", auc->number, auc->owner->name, stringf(34, ALIGN_LEFT, NULL, auc->item->short_descr), auc->item->level, auc->bid, IS_OBJ_STAT(auc->item, ITEM_QUEST) ? "qp" : "g ", 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); 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; } } }