1stMUD/corefiles/
1stMUD/gods/
1stMUD/player/
1stMUD/win32/
1stMUD/win32/ROM/
/**************************************************************************
*  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;
		}
	}
}