asgard/
asgard/.settings/
asgard/area/
asgard/data/clans/
asgard/data/clans/history/
asgard/data/rosters/
asgard/src/notice/
/*
 * newquest.c
 *
 *  Created on: 6 Jan 2011
 *      Author: Nico
 */
#include <stdlib.h>
#include <stdio.h>

#include "merc.h"
#include "recycle.h"
#include "string.h"
#include "newclan.h"
#include "newquest.h"
#include "pathfind.h"
#include "global_mods.h"
#include "achievements.h"

QITEM_FN_DEF(next_items);

QITEM_FN_DEF(quest_request);
QITEM_FN_DEF(quest_complete);
QITEM_FN_DEF(quest_quit);
QITEM_FN_DEF(quest_info);

QITEM_FN_DEF(item);
QITEM_FN_DEF(gmod);
QITEM_FN_DEF(corpse);

QITEM_FN_DEF(quest_put);
QITEM_FN_DEF(quest_take);
QITEM_FN_DEF(locker);

QITEM_FN_DEF(imm_hunger);
QITEM_FN_DEF(imm_thirst);

QITEM_FN_DEF(wpnflag);
QITEM_FN_DEF(aesirupgrade);

QITEM_FN_DEF(restring_item);

QITEM_FN_DEF(title_pretitle);
QITEM_FN_DEF(title_whotitle);

void do_say(CHAR_DATA *ch, char *argument);
void do_put(CHAR_DATA *ch, char *argument);
void do_get(CHAR_DATA *ch, char *argument);
bool is_safe_quiet(CHAR_DATA * ch, CHAR_DATA * victim);
BUFFER * display_stats( OBJ_DATA *obj, CHAR_DATA *ch, bool contents );
BUFFER *show_list_to_char(OBJ_DATA *list, CHAR_DATA *ch, bool fShort, bool fShowNothing);
void do_announce(CHAR_DATA *ch, char *argument);

QUEST_ITEM quest_item_title[] = {
	{	"pretitle",	0,	COST_QUEST,	7500,	QITEM_FN_NAME(title_pretitle),	NULL,	"change your pretitle"	},
	{	"whotitle",	0,	COST_QUEST,	10000,	QITEM_FN_NAME(title_whotitle),	NULL,	"change your pretitle"	},
	{	NULL,		0,	0,			0,		NULL,							NULL,	NULL					}
};

QUEST_ITEM quest_item_restring[] = {
	{	"short",	0,	COST_QUEST,	300,	QITEM_FN_NAME(restring_item),	NULL,	"restring the short name"	},
	{	"long",		0,	COST_QUEST,	300,	QITEM_FN_NAME(restring_item),	NULL,	"restring the long name"	},
	{	NULL,		0,	0,			0,		NULL,							NULL,	NULL						}
};

QUEST_ITEM quest_item_corpse[] = {
	{	"quest",	0,	COST_QUEST,	300,	QITEM_FN_NAME(corpse),	NULL,	"corpse retrieval with questpoints"	},
	{	"platinum",	0,	COST_PLAT,	600,	QITEM_FN_NAME(corpse),	NULL,	"corpse retrieval with platinum"	},
	{	NULL,		0,	0,			0,		NULL,					NULL,	NULL								}
};

QUEST_ITEM quest_item_vinir[] = {
	{	"dagger",		9921,	COST_QUEST,	3000,	QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"mace",			9918,	COST_QUEST,	3000,	QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"flail",		9922,	COST_QUEST,	3000,	QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"polearm",		9920,	COST_QUEST,	3000,	QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"spear",		9924,	COST_QUEST,	3000,	QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"axe",			9919,	COST_QUEST,	3000,	QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"sword",		9917,	COST_QUEST,	3000,	QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"whip",			9923,	COST_QUEST,	3000,	QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"platemail",	9912,	COST_QUEST,	3000,	QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"helmet",		9913,	COST_QUEST,	3000,	QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"legplates",	9907,	COST_QUEST,	3000,	QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"boots",		9911,	COST_QUEST,	3000,	QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"gauntlets",	9909,	COST_QUEST,	3000,	QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"armplates",	9908,	COST_QUEST,	3000,	QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"shield",		9910,	COST_QUEST,	3000,	QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"cape cloak",	9914,	COST_QUEST,	3000,	QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"bracer",		9906,	COST_QUEST,	3000,	QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"girth",		9916,	COST_QUEST,	3000,	QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"exotic",		9925,	COST_QUEST,	3000,	QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"mask",			9915,	COST_QUEST,	3000,	QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	NULL,			0,		0,			0,		NULL,					NULL,	NULL						}
};

QUEST_ITEM quest_item_aesir[] = {
	{	"sword",	9873,	COST_QUEST,	13500,		QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"greatsword",	9904,	COST_QUEST,	13500,		QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"dagger",	9874,	COST_QUEST,	13500,		QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
//	{	"mace",		9875,	COST_QUEST,	13500,		QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"mattock",	9929,	COST_QUEST,	13500,		QITEM_FN_NAME(item),	NULL,	"YOU SHUOLD NOT SEE THIS"	},
	{	"hammer",	9876,	COST_QUEST,	13500,		QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"flail",	9931,	COST_QUEST,	13500,		QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"ranseur",	9877,	COST_QUEST,	13500,		QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"staff",	9878,	COST_QUEST,	13500,		QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"spear",	9930,	COST_QUEST,	13500,		QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"axe",		9879,	COST_QUEST,	13500,		QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"adze",		9932,	COST_QUEST,	13500,		QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"whip",		9880,	COST_QUEST,	13500,		QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"platemail",	9881,	COST_QUEST,	13500,		QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"helmet",	9882,	COST_QUEST,	13500,		QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"legplates",	9891,	COST_QUEST,	13500,		QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"boots",	9883,	COST_QUEST,	13500,		QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"gauntlets",	9884,	COST_QUEST,	13500,		QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"armplates",	9885,	COST_QUEST,	13500,		QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"shield",	9886,	COST_QUEST,	13500,		QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"cape cloak",	9887,	COST_QUEST,	13500,		QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"bracer",	9888,	COST_QUEST,	13500,		QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"girth",	9889,	COST_QUEST,	13500,		QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"mask",		9890,	COST_QUEST,	13500,		QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"pack",		9905,	COST_QUEST,	3400,		QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	NULL,		0,	0,		0,		NULL,			NULL,	NULL			}
};

QUEST_ITEM quest_item_qitems[] = {
	{	"mask",		9853,	COST_QUEST,	2650,	QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"pod",		9851,	COST_QUEST,	2800,	QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"stone",	9926,	COST_QUEST,	3000,	QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	"light",	9852,	COST_QUEST,	3400,	QITEM_FN_NAME(item),	NULL,	"YOU SHOULD NOT SEE THIS"	},
	{	NULL,		0,		0,			0,		NULL,					NULL,	NULL						}
};

QUEST_ITEM quest_item_immunity[] = {
	{	"hunger",	0,	COST_QUEST,	1500,	QITEM_FN_NAME(imm_hunger),	NULL,	"immunity to hunger"	},
	{	"thirst",	0,	COST_QUEST,	1500,	QITEM_FN_NAME(imm_thirst),	NULL,	"immunity to thirst"	},
	{	NULL,		0,	0,			0,		NULL,						NULL,	NULL					}
};

// Hack to put in weapon flag bits.
QUEST_ITEM quest_item_wpnflags[] = {
	{	"flaming",	0,	COST_NOTAPPL,	WEAPON_FLAMING,		QITEM_FN_NAME(wpnflag),	NULL,	"flame weapon flag"		},
	{	"frosting",	0,	COST_NOTAPPL,	WEAPON_FROST,		QITEM_FN_NAME(wpnflag),	NULL,	"frost weapon flag"		},
	{	"shocking",	0,	COST_NOTAPPL,	WEAPON_SHOCKING,	QITEM_FN_NAME(wpnflag),	NULL,	"shock weapon flag"		},
	{	"sharp",	0,	COST_NOTAPPL,	WEAPON_SHARP,		QITEM_FN_NAME(wpnflag),	NULL,	"sharp weapon flag"		},
	{	"vorpal",	0,	COST_NOTAPPL,	WEAPON_VORPAL,		QITEM_FN_NAME(wpnflag),	NULL,	"vorpal weapon flag"	},
	{	"poisoned",	0,	COST_NOTAPPL,	WEAPON_POISON,		QITEM_FN_NAME(wpnflag),	NULL,	"poison weapon flag"	},
	{	"vampiric",	0,	COST_NOTAPPL,	WEAPON_VAMPIRIC,	QITEM_FN_NAME(wpnflag),	NULL,	"vampiric weapon flag"	},
	{	"osmotic",	0,	COST_NOTAPPL,	WEAPON_OSMOSIS,		QITEM_FN_NAME(wpnflag),	NULL,	"osmosis weapon flag"	},
	{	"draining",	0,	COST_NOTAPPL,	WEAPON_ENERGYDRAIN,	QITEM_FN_NAME(wpnflag), NULL,	"energydrain weapon flag"},
	{	NULL,		0,	0,				0,					NULL,					NULL,	NULL					}
};

QUEST_ITEM quest_item_gmods[] = {
	{	"xp0.25",		VNUM_XPVOUCHER_025,	COST_NOTAPPL,	25,		QITEM_FN_NAME(gmod),	NULL,	"+0.25 xpmod voucher"	},
	{	"xp0.50",		VNUM_XPVOUCHER_050,	COST_NOTAPPL,	50,		QITEM_FN_NAME(gmod),	NULL,	"+0.25 xpmod voucher"	},
	{	"xp0.75",		VNUM_XPVOUCHER_075,	COST_NOTAPPL,	75,		QITEM_FN_NAME(gmod),	NULL,	"+0.25 xpmod voucher"	},
	{	"xp1.00",		VNUM_XPVOUCHER_100,	COST_NOTAPPL,	100,	QITEM_FN_NAME(gmod),	NULL,	"+0.25 xpmod voucher"	},
	{	"xp1.25",		VNUM_XPVOUCHER_125,	COST_NOTAPPL,	125,	QITEM_FN_NAME(gmod),	NULL,	"+0.25 xpmod voucher"	},
	{	"xp1.50",		VNUM_XPVOUCHER_150,	COST_NOTAPPL,	150,	QITEM_FN_NAME(gmod),	NULL,	"+0.25 xpmod voucher"	},
	{	"xp1.75",		VNUM_XPVOUCHER_175,	COST_NOTAPPL,	175,	QITEM_FN_NAME(gmod),	NULL,	"+0.25 xpmod voucher"	},
	{	"xp2.00",		VNUM_XPVOUCHER_200,	COST_NOTAPPL,	200,	QITEM_FN_NAME(gmod),	NULL,	"+0.25 xpmod voucher"	},

	{	"quest0.25",	VNUM_QPVOUCHER_025,	COST_NOTAPPL,	25,		QITEM_FN_NAME(gmod),	NULL,	"+0.25 qpmod voucher"	},
	{	"quest0.50",	VNUM_QPVOUCHER_050,	COST_NOTAPPL,	50,		QITEM_FN_NAME(gmod),	NULL,	"+0.50 qpmod voucher"	},
	{	"quest0.75",	VNUM_QPVOUCHER_075,	COST_NOTAPPL,	75,		QITEM_FN_NAME(gmod),	NULL,	"+0.75 qpmod voucher"	},
	{	"quest1.00",	VNUM_QPVOUCHER_100,	COST_NOTAPPL,	100,	QITEM_FN_NAME(gmod),	NULL,	"+1.00 qpmod voucher"	},
	{	"quest1.25",	VNUM_QPVOUCHER_125,	COST_NOTAPPL,	125,	QITEM_FN_NAME(gmod),	NULL,	"+0.25 qpmod voucher"	},
	{	"quest1.50",	VNUM_QPVOUCHER_150,	COST_NOTAPPL,	150,	QITEM_FN_NAME(gmod),	NULL,	"+0.50 qpmod voucher"	},
	{	"quest1.75",	VNUM_QPVOUCHER_175,	COST_NOTAPPL,	175,	QITEM_FN_NAME(gmod),	NULL,	"+0.75 qpmod voucher"	},
	{	"quest2.00",	VNUM_QPVOUCHER_200,	COST_NOTAPPL,	200,	QITEM_FN_NAME(gmod),	NULL,	"+1.00 qpmod voucher"	},
	{	NULL,			0,	0,				0,				NULL,					NULL,	NULL,							}
};

QUEST_ITEM quest_items[] = {
	{	"title",	0,	COST_NOTAPPL,	0,		QITEM_FN_NAME(next_items),	quest_item_title,		"your whotitle or pretitle"	},
	{	"restring",	0,	COST_NOTAPPL,	0,		QITEM_FN_NAME(next_items),	quest_item_restring,	"item restringing"			},
	{	"corpse",	0,	COST_NOTAPPL,	0,		QITEM_FN_NAME(next_items),	quest_item_corpse,		"corpse retrieval"			},
	{	"vinir",	0,	COST_NOTAPPL,	0,		QITEM_FN_NAME(next_items),	quest_item_vinir,		"vinir items"				},
	{	"aesir",	0,	COST_NOTAPPL,	0,		QITEM_FN_NAME(next_items),	quest_item_aesir,		"aesir items"				},
	{	"upgrade",	0,	COST_QUEST,	10000,		QITEM_FN_NAME(aesirupgrade),	NULL,		"aesir upgrade"				},
	{	"qitems",	0,	COST_NOTAPPL,	0,		QITEM_FN_NAME(next_items),	quest_item_qitems,		"general quest items"		},
	{	"immunity",	0,	COST_NOTAPPL,	0,		QITEM_FN_NAME(next_items),	quest_item_immunity,	"immunity"					},
	{	"wpnflag",	0,	COST_NOTAPPL,	0,		QITEM_FN_NAME(next_items),	quest_item_wpnflags,	"weapon flags"				},
	{	"voucher",	0,	COST_NOTAPPL,	0,		QITEM_FN_NAME(next_items),	quest_item_gmods,		"redeem a xp/qpmod voucher"	},
	{	"locker",	0,	COST_QUEST,		2000,	QITEM_FN_NAME(locker),		NULL,					"your locker"				},
	{	"pill",		50,	COST_QUEST,		300,	QITEM_FN_NAME(item),		NULL,					"YOU SHOULD NOT SEE THIS"	},
	{	NULL,		0,	0,				0,		NULL,						NULL,					NULL						}
};

QUEST_ITEM quest_item_request = {
	"", 0, COST_NOTAPPL, 0, QITEM_FN_NAME(quest_request), NULL, NULL
};
QUEST_ITEM quest_item_complete = {
	"", 0, COST_NOTAPPL, 0, QITEM_FN_NAME(quest_complete), NULL, NULL
};
QUEST_ITEM quest_item_quit = {
	"", 0, COST_NOTAPPL, 0, QITEM_FN_NAME(quest_quit), NULL, NULL
};
QUEST_ITEM quest_item_info = {
	"", 0, COST_NOTAPPL, 0, QITEM_FN_NAME(quest_info), NULL, NULL
};
QUEST_ITEM quest_item_locker = {
	"", 0, COST_NOTAPPL, 0, QITEM_FN_NAME(locker), NULL, NULL
};

QUEST_VERB quest_verbs[] = {
	// Items.
#define QVERB_BUY		&quest_verbs[0]
	{	"buy",		TRUE,	quest_items,			"buy a quest item/service"						},
#define QVERB_SELL		&quest_verbs[1]
	{	"sell",		TRUE,	quest_items,			"sell back a quest item"						},
#define QVERB_BROWSE	&quest_verbs[2]
	{	"browse",	TRUE,	quest_items,			"browse or get info on items/services"			},
#define QVERB_LIST		&quest_verbs[3]
	{	"list",		TRUE,	quest_items,			"same as browse"								},

	// Quest control.
#define QVERB_REQUEST	&quest_verbs[4]
	{	"request",	TRUE,	&quest_item_request,	"request a quest"								},
#define QVERB_COMPLETE	&quest_verbs[5]
	{	"complete",	TRUE,	&quest_item_complete,	"hand in a quest"								},
#define QVERB_QUIT		&quest_verbs[6]
	{	"quit",		TRUE,	&quest_item_quit,		"quit a quest"									},
#define QVERB_INFO		&quest_verbs[7]
	{	"info",		FALSE,	&quest_item_info,		"get information on your current/pending quest"	},

	// Lockers.
#define QVERB_PUT		&quest_verbs[8]
	{	"put",		TRUE,	&quest_item_locker,		"put something in your locker"					},
#define QVERB_TAKE		&quest_verbs[9]
	{	"get",		TRUE,	&quest_item_locker,		"get something from your locker"				},
#define QVERB_INVEN		&quest_verbs[10]
	{	"inventory",TRUE,	&quest_item_locker,		"show whats in your locker"						},

	{	NULL,		FALSE,	NULL,					NULL											}
};

char *price_types[] = {
	"ERROR",
	"qps",
	"platinum",
	"n/a"
};

CHAR_DATA *get_qm(CHAR_DATA *ch) {
	CHAR_DATA *qm;

	for (qm = ch->in_room->people; qm != NULL; qm = qm->next_in_room)
		if (IS_NPC(qm) && can_see(ch, qm) && qm->spec_fun == spec_lookup("spec_questmaster"))
			return qm;

	return qm;
}

QUEST_VERB *get_verb(char *argument) {
	QUEST_VERB *verb;

	for (verb = quest_verbs; verb->name != NULL; verb++)
		if (!str_prefix(argument, verb->name))
			return verb;
	return NULL;
}

QUEST_ITEM *get_item(char *argument, QUEST_ITEM *table) {
	for (; table->name != NULL; table++)
		if (!str_prefix(argument, table->name))
			return table;
	return NULL;
}

bool check_price(CHAR_DATA *ch, CHAR_DATA *qm, QUEST_ITEM *item) {
	char buf[MAX_STRING_LENGTH];
	if (item == NULL)
		return FALSE;

	switch (item->cost_type) {
	case COST_QUEST:
		if (ch->questpoints >= item->cost)
			return TRUE;
		break;
	case COST_PLAT:
		if (ch->platinum >= item->cost)
			return TRUE;
		break;
	case COST_NOTAPPL:
		return TRUE;
	}

	if (qm) {
		sprintf(buf, "$n{x says '{SSorry, $N{S, you need %d %s for that.{x'",
			item->cost, price_types[item->cost_type]);
		act(buf, qm, NULL, ch, TO_VICT);
	} else {
		sprintf(buf, "You need %d %s for that.",
			item->cost, price_types[item->cost_type]);
		send_to_char(buf, ch);
	}
	return FALSE;
}

void deduct_price(CHAR_DATA *ch, QUEST_ITEM *item) {
	if (item == NULL)
		return;

	switch (item->cost_type) {
	case COST_QUEST:
		ch->questpoints -= item->cost;
		break;
	case COST_PLAT:
		ch->platinum -= item->cost;
		break;
	}
}
void add_price(CHAR_DATA *ch, QUEST_ITEM *item, float modifier) {
	if (item == NULL)
		return;
	int oldCost = item->cost;
	item->cost = (int)(-((float)item->cost)*modifier);
	deduct_price(ch, item);
	item->cost = oldCost;
}

void display_items(QUEST_ITEM *table, BUFFER *buffer) {
	char buf[MAX_STRING_LENGTH], price[MAX_STRING_LENGTH];
	OBJ_INDEX_DATA *obj;

	add_buf(buffer, "{GName       {B-{G Description                         {B-{G Cost{x\r\n");
	for (; table->name != NULL; table++) {
		if (table->cost_type == COST_NOTAPPL)
			sprintf(price, "{yvaries");
		else
			sprintf(price, "{R%d {w%.8s", table->cost, price_types[table->cost_type]);

		if (table->obj_vnum > 0)
			obj = get_obj_index(table->obj_vnum);
		else
			obj = NULL;

		// Prioritise object description over the table description.
		sprintf(buf, "{w%-10s {B- {x%s {B- %s{x\r\n",
			table->name, end_string(obj != NULL ? obj->short_descr : table->description, 35), price);
		add_buf(buffer, buf);
	}
}

void do_quest(CHAR_DATA *ch, char *argument) {
	char buf[MAX_STRING_LENGTH];
	QUEST_VERB *verb;
	QUEST_ITEM *item;
	CHAR_DATA *qm = NULL;

	if (IS_NPC(ch)) {
		send_to_char("NPCs can't quest.\r\n", ch);
		return;
	}

	if (argument[0] == '\0') {
		BUFFER *buffer = new_buf();

		add_buf(buffer, "Available commands ({R*{x indicates you need a QM):\r\n");
		for (verb = quest_verbs; verb->name != NULL; verb++) {
			sprintf(buf, "{R%c{w%-9s{B -{x %s\r\n",
				verb->need_qm ? '*' : ' ', verb->name, verb->description);
			add_buf(buffer, buf);
		}

		page_to_char(buffer->string, ch);
		free_buf(buffer);
		return;
	}

	argument = one_argument(argument, buf);

	if ((verb = get_verb(buf)) == NULL) {
		send_to_char("Invalid command. Use \"{Gquest{x\" without any arguments to see a list of commands.\r\n", ch);
		return;
	}

	if (verb->need_qm && (qm = get_qm(ch)) == NULL) {
		send_to_char("You need a quest master to do that.\r\n", ch);
		return;
	}

	if (verb->items == NULL) {
		printf_debug("do_quest: null handler for verb %s, ch %s", verb->name, ch->name);
		send_to_char("An error has occurred! Please tell an immortal.\r\n", ch);
		return;
	}

	// Hack for no-item lists.
	if (verb->items->name[0] == '\0')
		item = verb->items;
	else {
		if (argument[0] == '\0') {
			BUFFER *buffer = new_buf();

			add_buf(buffer, "Please specify an item type from the following:\r\n");
			display_items(verb->items, buffer);

			sprintf(buf, "\r\nSyntax: {wquest %s {R<item-type>{x\r\n", verb->name);
			add_buf(buffer, buf);

			page_to_char(buffer->string, ch);
			free_buf(buffer);
			return;
		}

		argument = one_argument(argument, buf);
		if ((item = get_item(buf, verb->items)) == NULL) {
			send_to_char("Invalid item choice.\r\n", ch);
			return;
		}
	}

	// Perform the work.
	(*item->func)(ch, qm, verb, item, argument);
}

void end_quest(CHAR_DATA *ch, int timer) {
	// Remove tokens.
	if (ch->qstate == QSTATE_OBJ) {
		ROOM_INDEX_DATA *room = get_room_index(ch->qroom);
		if (room != NULL) {
			OBJ_DATA *obj;
			for (obj = room->contents; obj != NULL; obj = obj->next_content) {
				if (obj->pIndexData->vnum == ch->qtarget && obj->owner != NULL && !str_cmp(obj->owner, ch->name)) {
					extract_obj(obj);
					break;
				}
			}
		}
	}
    ch->qstate  = QSTATE_NONE;
    ch->qtarget = 0;
    ch->qtimer  = timer;
    ch->qmvnum  = 0;
    ch->qroom   = 0;
}

QITEM_FN_DEF(next_items) {
	char buf[MAX_STRING_LENGTH];

	if (item->items == NULL) {
		printf_debug( "next_items: No items for verb %s on item %s for character %s and extraargs %s.",
			verb->name, item->name, ch->name, argument);
		send_to_char("Something has gone wrong! Please tell an immortal.\r\n", ch);
		return;
	}
	if (argument[0] == '\0') {
		BUFFER *buffer = new_buf();

		add_buf(buffer, "Please specify an item from the following:\r\n");
		display_items(item->items, buffer);

		sprintf(buf, "\r\nSyntax: {wquest %s %s {R<item>{x\r\n", verb->name, item->name);
		add_buf(buffer, buf);

		page_to_char(buffer->string, ch);
		free_buf(buffer);
		return;
	}
	argument = one_argument(argument, buf);
	if ((item = get_item(buf, item->items)) == NULL) {
		send_to_char("Invalid item choice.\r\n", ch);
		return;
	}

	(*item->func)(ch, qm, verb, item, argument);
}

QITEM_FN_DEF(quest_request) {
	char buf[MAX_STRING_LENGTH];
	AREA_DATA *pArea;
	ROOM_INDEX_DATA *room;
	CHAR_DATA *mob;
	OBJ_DATA *obj;
	int type = number_range(QTYPE_MIN, QTYPE_MAX), vnum = 0, count;
	bool found = FALSE;

	if (ch->qstate == QSTATE_COMPLETE) {
		act("$n{x says '{SWhy don't you tell me about how you completed you last quest first, $N{S?{x'", qm, NULL, ch, TO_VICT);
		return;
	}
	if (ch->qstate != QSTATE_NONE) {
		act( "$n{x says '{SYou're still on a quest, $N{S.{x'", qm, NULL, ch, TO_VICT );
		return;
	}
	if (ch->qtimer > 0) {
		act( "$n{x says '{SYou can't quest yet, $N{S. Give others a chance.{x'", qm, NULL, ch, TO_VICT );
		return;
	}

	// 10000 tries to get a target.
	for (count = 0; count < 10000; room = NULL, count++) {
		vnum = number_range(300, 60000);
		if ((room = get_room_index(vnum)) == NULL || (pArea = room->area) == NULL)
			continue;

		if (pArea->continent != ch->in_room->area->continent
		|| 	strstr(pArea->builders, "Unlinked")
		|| 	strstr(pArea->builders, "Noquest")
		||	IS_SET(room->room_flags, ROOM_NO_MOB)
		||	IS_SET(room->room_flags, ROOM_SAFE)
		||	IS_SET(room->room_flags, ROOM_NO_MAGIC)
		||	IS_SET(room->room_flags, ROOM_NO_RECALL)
		||	IS_SET(room->room_flags, ROOM_IMP_ONLY)
		||	IS_SET(room->room_flags, ROOM_GODS_ONLY)
		||	IS_SET(room->room_flags, ROOM_HEROES_ONLY)
		||	IS_SET(room->room_flags, ROOM_NEWBIES_ONLY)
		||	IS_SET(room->room_flags, ROOM_PET_SHOP)
		||	IS_SET(room->room_flags, ROOM_SHOP)
		||	IS_SET(room->room_flags, ROOM_PRIVATE)
		||	IS_SET(room->room_flags, ROOM_SOLITARY)
		||	IS_SET(room->room_flags, ROOM_ARENA)
		||  bfs_pathfind(ch->in_room, pf_end_at_room(room), pf_filt_normal(ch), PF_MAX_DEPTH, FALSE) < 0)
			continue;

		switch (type) {
		case QSTATE_MOB:
			for (mob = room->people; mob != NULL; mob = mob->next_in_room) {
				int lvl_diff;
				if (!IS_NPC(mob) || is_safe_quiet(ch, mob))
					continue; // Deal with the basics first.

				// Alignment must be different.
				if (IS_EVIL(ch) == IS_EVIL(mob))
					continue;

				lvl_diff = mob->level - ch->level;
				// < LGD: -20 < lvl < 20, LGD: -20 < lvl < 50
				if (abs(lvl_diff) < 20 || (ch->level == LEVEL_HERO && lvl_diff > 0 && lvl_diff < 50))
					break;
			}
			if (mob != NULL) {
				sprintf( buf, "$n{x says '{SAsgard's most heinous criminal, %s{S has escaped from the dungeons!{x'",
						mob->short_descr );
				act( buf, qm, NULL, ch, TO_VICT );
				sprintf( buf, "$n{x says '{SOur court wizardess has located it somewhere in the region of %s{S in %s{S.{x'",
						room->name, pArea->name );
				act( buf, qm, NULL, ch, TO_VICT );
				act( "$n{x says '{SThe penalty of this crime is DEATH.{x'", qm, NULL, ch, TO_VICT );
				act( "$n{x says '{SWe're counting on you, $N{S, to carry out the sentence.{x'", qm, NULL, ch, TO_VICT );
				vnum = mob->pIndexData->vnum;
				found = TRUE;
			}
			break;
		case QSTATE_OBJ:
			if ((obj = create_object(get_obj_index(number_range(QTOKEN_LOWER, QTOKEN_UPPER)), 0)) != NULL) {
				free_string(obj->owner);
				obj->owner = str_dup(ch->name);
				obj_to_room(obj, room);
				act("$n{x says '{SA vile fiend has stolen a $p{S from the town treasury!{x'", qm, obj, ch, TO_VICT );
				sprintf(buf, "$n{x says '{SOur court wizardess has located it somewhere in the region of %s{S in %s{S.{x'",
						room->name, pArea->name);
				act(buf, qm, NULL, ch, TO_VICT);
				act("$n{x says '{SWe're counting on you, $N{S, to recover it. May the Gods be with you!{x'", qm, NULL, ch, TO_VICT);
				vnum = obj->pIndexData->vnum;
				found = TRUE;
			}
			break;
		}
		if (found) {
			ch->qstate	= type;
			ch->qtarget	= vnum;
			ch->qmvnum	= qm->pIndexData->vnum;
			ch->qtimer	= number_range(10, 30);
			ch->qroom	= room->vnum;
			sprintf(buf, "$n{x says '{SYou have %d ticks to complete this quest.{x'", ch->qtimer);
			act( buf, qm, NULL, ch, TO_VICT );
			act( "$n{x says '{SMay the Gods be with you!{x'", qm, NULL, ch, TO_VICT );
			return;
		}
	}
	act("$n{x says '{SI'm sorry, $N{S, but I can't find a quest for you at the moment.{x'", qm, NULL, ch, TO_VICT);
	ch->qtimer	= 3;
}

QITEM_FN_DEF(quest_complete) {
	act("$n informs $N $e has completed $s quest.", ch, NULL, qm, TO_ROOM);
	act("You inform $N you have completed $s quest.", ch, NULL, qm, TO_CHAR);

	if (ch->qstate == QSTATE_NONE) {
		act("$n{x says '{SBut you're not on a quest, $N{S.{x'", qm, NULL, ch, TO_VICT);
		return;
	}

	if (ch->qmvnum != qm->pIndexData->vnum) {
		act("$n{x says '{SI think you may have got the wrong person, $N{S.{x'", qm, NULL, ch, TO_VICT);
		return;
	}

	if (ch->qstate == QSTATE_OBJ) {
		OBJ_DATA *obj;
		for (obj = ch->carrying; obj != NULL; obj = obj->next_content) {
			if (obj->pIndexData->vnum == ch->qtarget) {
				act( "You hand $p{x over to $N{x, who accepts it graciously.", ch, obj, qm, TO_CHAR );
				act( "$n{x hands $p{x over to $N{x, who accepts it graciously.", ch, obj, qm, TO_ROOM );
				extract_obj(obj);
				// Yes, messy.
				goto questcomplete;
			}
		}
	}

	if (ch->qstate != QSTATE_COMPLETE) {
		act("$n{x says '{SBut you haven't finished your quest yet, $N{S.{x'", qm, NULL, ch, TO_VICT);
		return;
	}

questcomplete:
	act("$n{x says '{SThank you for completing the quest I gave you, $N{S!{x'", qm, NULL, ch, TO_VICT);

	char buf[MAX_STRING_LENGTH];
	int rewardQuest	= number_range( 15, 40 );
	int rewardPlat	= number_range( 5, 15 );
	int rewardExp	= number_range( 50, 350 );
	gmod_apply(GMOD_QP, &rewardQuest);
	gmod_apply(GMOD_QP, &rewardExp);
	gmod_apply(GMOD_QP, &rewardPlat);

	sprintf(buf, "$n{x says '{SAs a reward, I am giving you %d quest points, %d platinum and %d experience points! (%.2fx mod){x'",
			rewardQuest, rewardPlat, rewardExp, gmod_get_mult(GMOD_QP));
	act(buf, qm, NULL, ch, TO_VICT);

	ch->questpoints	+= rewardQuest;
	ch->platinum	+= rewardPlat;
	gain_exp(ch, rewardExp, TRUE, TRUE);

	if ( number_percent() < 5 ) {
		int rewardPrac	= number_range( 2, 5 );
		sprintf(buf, "$n{x says '{SAlso, for being such a good sport, I am awarding you %d practice points!{x'",
				rewardPrac);
		act(buf, qm, NULL, ch, TO_VICT);
		ch->practice	+= rewardPrac;
	}

	// Super-bonus prize (like the iquest pill before).
	if (number_percent() < 3) {
		rewardQuest	= number_range(300, 350);
		gmod_apply(GMOD_QP, &rewardQuest);
		sprintf(buf, "$n{x says '{SDING DING DING! YOU'VE WON THE JACKPOT OF %d QUESTPOINTS!{x'",
			rewardQuest);
		act(buf, qm, NULL, ch, TO_VICT);
		ch->questpoints	+= rewardQuest;
	}

	// Another super-bonus prize - a voucher to increase rewards.
	if (number_percent() < 3) {
		OBJ_INDEX_DATA *voucherIndex = get_obj_index(number_range(907, 914));
		OBJ_DATA *voucher = voucherIndex != NULL ? create_object(voucherIndex, voucherIndex->level) : NULL;
		if (voucher != NULL) {
			sprintf(buf, "$n{x says '{SJust as another little bonus, I'm giving you a %s{S!{x'",
       			voucher->short_descr);
			act(buf, qm, NULL, ch, TO_VICT);
			obj_to_char(voucher, ch);
		}
	}

	// Yet another bonus.
	if (number_percent() < 3 && gmod_add(GMOD_XP, 0.50f)) {
		act("$n{x says '{SI'm so impressed, I've increased the experience modifier for everyone!{x'", qm, NULL, ch, TO_VICT);
		sprintf(buf, "%s{Y has increased the experience modifier by {G+0.50x{Y to a total of {G%.2fx{Y!",
			qm->short_descr, gmod_get_mult(GMOD_XP));
		do_announce(ch, buf);
	}

	// Chance to quest again straight away.
	if (number_percent() < 2) {
		act("$n{x nudges you and says '{STell you what, $N{S, I'm going to let you quest again straight away if you want!{x'", qm, NULL, ch, TO_VICT);
		end_quest(ch, 0);
	} else
		end_quest(ch, 10);

	// Achievement monitoring.
	ach_increment(ch, ACH_QUESTS, 1);
}

QITEM_FN_DEF(quest_quit) {
	act("$n informs $N that he is giving up on $S quest.", ch, NULL, qm, TO_ROOM);
	act("You inform $N that you are giving up on your quest.", ch, NULL, qm, TO_CHAR);

	if (ch->qstate == QSTATE_NONE) {
		act("$n{x says '{SBut you're not on a quest, $N{S.{x'", qm, NULL, ch, TO_VICT);
		return;
	}
	if (ch->qmvnum != qm->pIndexData->vnum) {
		act("$n{x says '{SI think you may have got the wrong person, $N{S.{x'", qm, NULL, ch, TO_VICT);
		return;
	}
	if (ch->qstate == QSTATE_COMPLETE) {
		act("$n{x says '{SBut you've already completed your quest, $N{S!{x'", qm, NULL, ch, TO_VICT);
		return;
	}

	act("$n{x says '{SI'm sorry to hear that, $N{S. You'll have to wait now.{x'", qm, NULL, ch, TO_VICT);
	end_quest(ch, 15);
}

QITEM_FN_DEF(quest_info) {
	char buf[MAX_STRING_LENGTH];

	BUFFER *buffer = new_buf();
	add_buf(buffer, "{B+- {GQuest Info{B ---------------------------+\r\n");
	if (ch->qstate != QSTATE_NONE) {
		sprintf(buf, "{B| {wState:  {y%-30.30s {B|\r\n",
			ch->qstate == QSTATE_COMPLETE ? "Complete" : "Ongoing" );
		add_buf(buffer, buf);

		if (ch->qstate == QSTATE_MOB) {
			MOB_INDEX_DATA *mob = get_mob_index(ch->qtarget);
			sprintf(buf, "{B| {wTarget: {B({wMOB{B){x %s {B|\r\n",
				end_string(mob ? mob->short_descr : "NULL", 24));
			add_buf(buffer, buf);
		} else if (ch->qstate == QSTATE_OBJ) {
			OBJ_INDEX_DATA *obj = get_obj_index(ch->qtarget);
			sprintf(buf, "{B| {wTarget: {B({wOBJ{B){x %s {B|\r\n",
				end_string(obj ? obj->short_descr : "NULL", 24));
			add_buf(buffer, buf);
		}

		ROOM_INDEX_DATA *room = get_room_index(ch->qroom);
		sprintf(buf, "{B| {wRoom:   {y%s {B|\r\n",
			end_string(room ? room->name : "NULL", 30) );
		add_buf(buffer, buf);
		sprintf(buf, "{B| {wArea:   {y%s {B|\r\n",
			end_string(room ? room->area->name : "NULL", 30) );
		add_buf(buffer, buf);
	}

	sprintf(buf, "{B|{w Time:   {y%-12d %17s {B|\r\n",
		ch->qtimer, ch->qstate == QSTATE_NONE ? "(till next quest)" : "");
	add_buf(buffer, buf);

	add_buf(buffer, "{B+----------------------------------------+{x\r\n");
	page_to_char(buffer->string, ch);
	free_buf(buffer);
}

QITEM_FN_DEF(item) {
	char buf[MAX_STRING_LENGTH];
	OBJ_INDEX_DATA *objIndex = get_obj_index(item->obj_vnum);
	OBJ_DATA *obj = objIndex ? create_object(objIndex, objIndex->level) : NULL;

	if (obj == NULL)
		sprintf(buf, "quest item: NULL object for item %s vnum %d.",
			item->name, item->obj_vnum);
	else if (verb == QVERB_BUY) {
		if (!check_price(ch, qm, item))
			return;

		deduct_price(ch, item);
		obj_to_char(obj, ch);
		act("$n{x digs around in $s cupboard for something, emerging with $p{x.", qm, obj, NULL, TO_ROOM);
		act("$N{x gives you $p{x.", ch, obj, qm, TO_CHAR);
		act("$N{x gives $n{x $p{x.", ch, obj, qm, TO_ROOM);
		do_say(qm, "Pleasure doing business with you!");
		return;
	} else if (verb == QVERB_SELL) {
		extract_obj(obj);
		for (obj = ch->carrying; obj != NULL; obj = obj->next_content)
			if (obj->pIndexData->vnum == item->obj_vnum)
				break;
		if (obj == NULL)
			act("$n{x says '{SYou don't have it, $N{S.{x'", qm, NULL, ch, TO_VICT);
		else {
			float mod = 0.80f;
			// Nasty hack for aesir junk.
			if ((item->obj_vnum >= 9873 && item->obj_vnum <= 9905) || (item->obj_vnum >= 9929 && item->obj_vnum <= 9932))
				mod = 0.869565f;
			add_price(ch, item, mod);
	        act("$n{x takes $p{x, dusts it off and puts it into $s cupboard.", qm, obj, NULL, TO_ROOM);
			do_say(qm, "Pleasure doing business with you!");
            extract_obj(obj);
		}
		return;
	} else if (verb == QVERB_BROWSE || verb == QVERB_LIST) {
		BUFFER *stats = display_stats(obj, ch, FALSE);
		page_to_char(stats->string, ch);
		free_buf(stats);
		extract_obj(obj);
		return;
	} else
		sprintf(buf, "quest item: Invalid verb %s on item %s for character %s and extraargs %s.",
			verb->name, item->name, ch->name, argument);
	printf_debug( buf);
	send_to_char("Something has gone wrong! Please tell an immortal.\r\n", ch);
}

QITEM_FN_DEF(gmod) {
	if (verb != QVERB_SELL) {
		send_to_char("You can only {Rsell{x a voucher.\r\n", ch);
		return;
	}

	OBJ_DATA *voucher;
	for (voucher = ch->carrying; voucher != NULL; voucher = voucher->next_content) {
		if (voucher->wear_loc == WEAR_NONE && voucher->pIndexData->vnum == item->obj_vnum)
			break;
	}

	if (voucher == NULL) {
		act( "$n{x says '{SYou're not carrying the right voucher, $N{S.{x'", qm, NULL, ch, TO_VICT );
		return;
	}

	// Hacky, but meh.
	GMOD_TYPE type;
	if (!str_prefix("xp", item->name))
		type = GMOD_XP;
	else if (!str_prefix("quest", item->name))
		type = GMOD_QP;
	else {
		printf_debug("Unknown modifier type: %s.", item->name);
		act( "$n{x says '{SI seem to have broken, please tell an immortal, $N{S.{x'", qm, NULL, ch, TO_VICT );
		return;
	}

	if (gmod_add(type, ((float)item->cost)/100.0f)) {
		char buf[MAX_STRING_LENGTH];
		act("$N{x takes $p{x from you.", ch, voucher, qm, TO_CHAR);
		extract_obj(voucher);
		sprintf(buf, "A {G+%0.2fx{Y %s voucher has just been redeemed, increasing the modifier to {G%.2fx{Y!",
			((float)item->cost)/100.0f, gmod_get_name(type), gmod_get_mult(type));
		do_announce(ch, buf);
		act("$n{x says '{SPleasure doing business with you, $N{S.{x'", qm, NULL, ch, TO_VICT);
		ach_increment(ch, ACH_VOUCHERS, 1);
	} else {
		act("$n{x says '{SSorry, $N{S, the modifier can't be increased at the moment.{x'", qm, NULL, ch, TO_VICT);
	}
}

QITEM_FN_DEF(corpse) {
	OBJ_DATA *obj;

	if (verb != QVERB_BUY) {
		send_to_char("You can only {Rbuy{x corpse retrieval.\r\n", ch);
		return;
	}

	for (obj = object_list; obj != NULL; obj = obj->next)
		if (obj->in_room != NULL
		&&  obj->item_type == ITEM_CORPSE_PC
		&& !str_cmp(obj->owner, ch->name))
			break;

	if (obj == NULL) {
		act( "$n{x says '{SYou don't have any corpses out there, $N{S.{x'", qm, NULL, ch, TO_VICT );
		return;
	}

	if (!check_price(ch, qm, item))
		return;

	deduct_price(ch, item);
	for (obj = object_list; obj != NULL; obj = obj->next) {
		if (obj->in_room != NULL
		&&  obj->item_type == ITEM_CORPSE_PC
		&& !str_cmp(obj->owner, ch->name)) {
			obj_from_room(obj);
			obj_to_char(obj, ch);
		}
	}
	send_to_char("You belongings appear in your hands!", ch);
}

void set_locker_name(CHAR_DATA *ch) {
	char buf[MAX_STRING_LENGTH];
	sprintf(buf, "locker%s", ch->name);
	free_string(ch->locker->name);
	ch->locker->name = str_dup(buf);
	sprintf(buf, "a locker belonging to %s", ch->name);
	free_string(ch->locker->short_descr);
	ch->locker->short_descr = str_dup(buf);
	free_string(ch->locker->description);
	ch->locker->description = str_dup(buf);
}

QITEM_FN_DEF(locker) {
	char buf[MAX_STRING_LENGTH];
	if (verb == QVERB_BUY) {
		if (!check_price(ch, qm, item))
			return;

		OBJ_INDEX_DATA *lockerIndex = get_obj_index(LOCKER_VNUM);

		if (lockerIndex == NULL) {
			send_to_char("BUG! No lockers available. Please tell an immortal.\r\n", ch);
			return;
		}

		if (ch->locker == NULL) {
			if ((ch->locker = create_object(lockerIndex, lockerIndex->level)) == NULL) {
				send_to_char("BUG! Could not create your locker. Please tell an immortal.\r\n", ch);
				return;
			}
			set_locker_name(ch);
		} else {
			// Expand.
			ch->locker->value[0] += lockerIndex->value[0];
			ch->locker->value[3] += lockerIndex->value[3];
		}
		deduct_price(ch, item);
		act("$n{x says '{SPleasure doing business with you, $N{S!{x'", qm, NULL, ch, TO_VICT);
		sprintf(buf, "$n{x says '{SYour locker now has a capacity of %d, and can hold items that are as heavy as %d.{x'",
			ch->locker->value[3]*10, ch->locker->value[0]*10);
		act(buf, qm, NULL, ch, TO_VICT);
    } else if (ch->locker == NULL)
        act( "$n{x says '{SYou don't have a locker, $N{S.{x'", qm, NULL, ch, TO_VICT );
    else if (verb == QVERB_BROWSE || verb == QVERB_LIST || verb == QVERB_INVEN) {
        BUFFER *buffer = show_list_to_char(ch->locker->contains, ch, TRUE, TRUE);
        send_to_char("Your locker contains:\r\n", ch);
        sprintf(buf, "Your locker capacity is %d with maximum object size of %d.\r\n",
            ch->locker->value[3]*10, ch->locker->value[0]*10);
        add_buf(buffer, buf);
        page_to_char(buffer->string, ch);
        free_buf(buffer);
	} else if (verb == QVERB_SELL)
		act( "$n{x says '{SI don't want your locker space, $N{S!{x'", qm, NULL, ch, TO_VICT );
	else if (verb == QVERB_PUT) {
		// Hack so we can reuse do_put code.
		obj_to_room(ch->locker, ch->in_room);
		argument = one_argument(argument, buf);
		strcat(buf, " locker");
		strcat(buf, ch->name);
		do_put(ch, buf);
		obj_from_room(ch->locker);
	} else if (verb == QVERB_TAKE) {
		// Hack so we can reuse do_get code.
		obj_to_room(ch->locker, ch->in_room);
		argument = one_argument(argument, buf);
		strcat(buf, " locker");
		strcat(buf, ch->name);
		do_get(ch, buf);
		obj_from_room(ch->locker);
	} else {
		printf_debug( "locker: Invalid verb %s for item %s, character %s",
			verb->name, item->name, ch->name);
	}
}

QITEM_FN_DEF(imm_hunger) {
	if (verb != QVERB_BUY) {
		send_to_char("You can only {Rbuy{x immunity to hunger.\r\n", ch);
		return;
	}

	if (ch->pcdata->condition[COND_HUNGER] == -1) {
		send_to_char("You are already immune to hunger.\r\n", ch);
		return;
	}

	if (!check_price(ch, qm, item))
		return;

	ch->pcdata->condition[COND_HUNGER] = -1;
	deduct_price(ch, item);

	act("$n{x sticks a knife into $N{x's gut and cuts $s stomach out.", qm, NULL, ch, TO_NOTVICT);
	act("$N{x sticks a knife into your gut and cuts your stomach out.", ch, NULL, qm, TO_CHAR);
	send_to_char("You feel perpetually full.\n\r", ch);
}

QITEM_FN_DEF(imm_thirst) {
	if (verb != QVERB_BUY) {
		send_to_char("You can only {Rbuy{x immunity to thirst.\r\n", ch);
		return;
	}

	if (ch->pcdata->condition[COND_THIRST] == -1) {
		send_to_char("You are already immune to thirst.\r\n", ch);
		return;
	}

	if (!check_price(ch, qm, item))
		return;

	ch->pcdata->condition[COND_THIRST] = -1;
	deduct_price(ch, item);

	act("$n{x sticks a knife into $N{x's head and cuts $s hypothalamus out.", qm, NULL, ch, TO_NOTVICT);
	act("$N{x sticks a knife into your gut and cuts your hypothalamus out.", ch, NULL, qm, TO_CHAR);
	send_to_char("Your thirst has been permanently quenched.\n\r", ch);
}

int calc_wpnflag_cost(OBJ_DATA *weapon, QUEST_ITEM *weapon_flag, CHAR_DATA *ch, CHAR_DATA *qm) {
	QUEST_ITEM *chkflags;
	int cost = 1;

	for (chkflags = quest_item_wpnflags; chkflags->name != NULL; chkflags++) {
		if (IS_WEAPON_STAT(weapon, chkflags->cost)) {
			AFFECT_DATA *wpnaff;
			bool foundtemp = FALSE, foundperm = FALSE;
			for (wpnaff = weapon->affected; wpnaff != NULL; wpnaff = wpnaff->next) {
				if (wpnaff->where == TO_WEAPON
				&&  wpnaff->bitvector == chkflags->cost) {
					if (wpnaff->duration < 0)
						foundperm = TRUE;
					else
						foundtemp = TRUE;
				}
			}
			// Found a matching temporary weapon flag (but no perm flag to stop cheaters from exploiting).
			if (foundtemp && !foundperm)
				continue;
			if (chkflags == weapon_flag) {
				char buf[MAX_STRING_LENGTH];
				sprintf(buf, "$n{x says '{SYour weapon is already %s, $N{S!{x'", weapon_flag->name);
				act(buf, qm, NULL, ch, TO_VICT);
				return -1;
			}
			cost++;
		}
	}

	return cost*cost*1500;
}

QITEM_FN_DEF(aesirupgrade) {
	if (argument[0] == '\0') {
		act("$n{x says '{SWhat item would you like me to upgrade, $N{S?{x'", qm, NULL, ch, TO_VICT);
		act("$n{x says '{SEach upgrade increases an Aesir item's stats by 10\% to a maximum of 100%.{S{x'", qm, NULL, ch, TO_VICT);
		act("$n{x says '{SWeapons increase 20\% per upgrade. Weapon dice however do not change{S.{x'", qm, NULL, ch, TO_VICT);
	//	act("$n{x says '{SOne final note: AC stat increases are added as an affect.{x'", qm, NULL, ch, TO_VICT);
		return;
	}

	OBJ_DATA *aesir;

	if ((aesir = get_obj_carry(ch, argument)) == NULL) {
		act("$n{x says '{SYou don't seem to have that, $N{S.{x'", qm, NULL, ch, TO_VICT);
		return;
	}

	if ((aesir->pIndexData->vnum >= 9873 && aesir->pIndexData->vnum <= 9905) || (aesir->pIndexData->vnum >= 9929 && aesir->pIndexData->vnum <= 9932)) { 
	}
	else {
		act("$n{x says '{SYou don't seem to have an aesir piece, $N{S.{x'", qm, NULL, ch, TO_VICT);
		return;
	}

	int cost = 10000;

	if (verb == QVERB_BROWSE || verb == QVERB_LIST) {
		char buf[MAX_STRING_LENGTH];
		sprintf(buf, "$n{x says '{SIt will cost %d questpoints to upgrade the %s{S, $N{S.{x'", cost, aesir->pIndexData->short_descr);
		act(buf, qm, NULL, ch, TO_VICT);
		return;
	} else if (verb != QVERB_BUY) {
		send_to_char("You can only {Rbrowse{x or {Rbuy{x weapon flags.\r\n", ch);
		return;
	}

	char buf[MAX_STRING_LENGTH];

	if (ch->questpoints < cost) {
		sprintf(buf, "$n{x says '{SSorry, $N{S, you need %d questpoints for that.{x'", cost);
		act(buf, qm, NULL, ch, TO_VICT);
		return;
	}

	if (aesir->tier_level >= 10) {
		sprintf(buf, "$n{x says, '{SI'm sorry $N{S, but your %s{S is already maxed out.{x'", aesir->pIndexData->short_descr);
		act(buf, qm, NULL, ch, TO_VICT);
		return;
	}

	ch->questpoints -= cost;
	OBJ_INDEX_DATA *oldaesir;
	AFFECT_DATA af;

	// Strip any old effects.
	AFFECT_DATA *paf, *paf_next;
	for (paf = aesir->affected; paf != NULL; paf = paf_next) {
		paf_next = paf->next;
		affect_remove_obj(aesir, paf);
	}

	// Grab appropriate aesir piece.	
	oldaesir  = get_obj_index(aesir->pIndexData->vnum);

	if (oldaesir == NULL) {
		ch->questpoints += cost;
		sprintf(buf, "$n{x says '{SSorry $N{S, I appear to be confused!{x'"); 
		act(buf, qm, NULL, ch, TO_VICT);
		return;
	}

	aesir->tier_level += 1;

	// Add upgraded keyword
	if (aesir->tier_level == 1) {
		char buf[MSL];
		sprintf(buf, "%s %s", aesir->name, "upgraded");
		free_string(aesir->name);
		aesir->name = str_dup(buf);
	}

	// Modify AC
	if (aesir->item_type == ITEM_ARMOR) {
		aesir->value[0] = oldaesir->value[0] + (oldaesir->value[0] * aesir->tier_level / 10);
		aesir->value[1] = oldaesir->value[1] + (oldaesir->value[1] * aesir->tier_level / 10);
		aesir->value[2] = oldaesir->value[2] + (oldaesir->value[2] * aesir->tier_level / 10);
		aesir->value[3] = oldaesir->value[3] + (oldaesir->value[3] * aesir->tier_level / 10);
	}
/*	if (aesir->item_type == ITEM_ARMOR) {
		af.where = TO_AFFECTS;
		af.type = 1; 
		af.level = aesir->level;
		af.duration = -1;
		af.location = APPLY_AC;
		af.modifier = ((aesir->value[0] + aesir->value[1] + aesir->value[2] + aesir->value[3]) / 4 * aesir->tier_level / 10) * -1;
		af.bitvector = 0;
		affect_to_obj(aesir, &af);
	}  */
	else if (aesir->item_type == ITEM_WEAPON) {
		aesir->tier_level += 1; // Weapons increase twice as fast.
	}

	// Add in original aesir effects.
	for (paf = oldaesir->affected; paf != NULL; paf = paf_next) {
		paf_next = paf->next;

		if ((paf->modifier * aesir->tier_level / 10) != 0) {
			af.where = paf->where;
			af.type = paf->type;
			af.level = paf->level;
			af.duration = paf->duration;
			af.location = paf->location;
			af.modifier = (paf->modifier * aesir->tier_level / 10);
			af.bitvector = paf->bitvector;
			affect_to_obj(aesir, &af);
		}
	}
	
	sprintf(buf, "$n{x says '{SYour %s{S now has a %d0%% bonus, $N{S!{x'", aesir->pIndexData->short_descr, aesir->tier_level); 
	act(buf, qm, NULL, ch, TO_VICT);
}

QITEM_FN_DEF(wpnflag) {
	if (argument[0] == '\0') {
		act("$n{x says '{SWhat weapon would you like me to flag, $N{S?{x'", qm, NULL, ch, TO_VICT);
		return;
	}

	OBJ_DATA *weapon;

	if ((weapon = get_obj_carry(ch, argument)) == NULL) {
		act("$n{x says '{SYou don't seem to have that, $N{S.{x'", qm, NULL, ch, TO_VICT);
		return;
	}

	if (weapon->item_type != ITEM_WEAPON) {
		act("$n{x says '{SYoucan only flag weapons, $N{S.{x'", qm, NULL, ch, TO_VICT);
		return;
	}

	if (verb == QVERB_BROWSE || verb == QVERB_LIST) {
		int cost = calc_wpnflag_cost(weapon, item, ch, qm);
		if (cost >= 0) {
			char buf[MAX_STRING_LENGTH];
			sprintf(buf, "$n{x says '{SIt will cost %d questpoints to put a %s flag on that weapon, $N{S.{x'", cost, item->name);
			act(buf, qm, NULL, ch, TO_VICT);
		}
		return;
	} else if (verb != QVERB_BUY) {
		send_to_char("You can only {Rbrowse{x or {Rbuy{x weapon flags.\r\n", ch);
		return;
	}

	char buf[MAX_STRING_LENGTH];
	int cost = calc_wpnflag_cost(weapon, item, ch, qm);

	if (cost < 0)
		return;

	if (ch->questpoints < cost) {
		sprintf(buf, "$n{x says '{SSorry, $N{S, you need %d questpoints for that.{x'", cost);
		act(buf, qm, NULL, ch, TO_VICT);
		return;
	}

	ch->questpoints -= cost;
	SET_BIT(weapon->value[4], item->cost);

	// Strip any old effects.
	AFFECT_DATA *wpnaff, *wpnaff_next;
	for (wpnaff = weapon->affected; wpnaff != NULL; wpnaff = wpnaff->next) {
		wpnaff_next = wpnaff->next;
		if (wpnaff->where == TO_WEAPON
		&&  wpnaff->bitvector == item->cost)
			affect_remove_obj(weapon, wpnaff);
	}
	sprintf(buf, "$n{x says '{SYour weapon is now permanently %s, $N{S!{x'", item->name);
	act(buf, qm, NULL, ch, TO_VICT);
}

QITEM_FN_DEF(restring_item) {
	char buf[MAX_STRING_LENGTH];
	OBJ_DATA *obj;

	if (verb != QVERB_BUY) {
		send_to_char("You can only {Rbuy{x restrings.\r\n", ch);
		return;
	}

	if (!check_price(ch, qm, item))
		return;

	if (argument[0] == '\0') {
		act("$n{x says '{SWell what do you want me to restring for you, $N{S?{x'", qm, NULL, ch, TO_VICT);
		return;
	}

	argument = one_argument(argument, buf);
	if ((obj = get_obj_carry(ch, buf)) == NULL)
	{
		act("$n{x says '{SYou can't restring non-existant objects, $N{S.{x'", qm, NULL, ch, TO_VICT);
		return;
	}

	if (IS_OBJ_STAT(obj, ITEM_NORESTRING)) {
		act("$n{x says '{SYou can't restring that, $N{x.{x'", qm, NULL, ch, TO_VICT);
		return;
	}

	if (argument[0] == '\0') {
		act("$n{x says '{SWell what do you want to restring it as, $N{S?{x'", qm, NULL, ch, TO_VICT);
		return;
	}

	if (!str_cmp(item->name, "short")) {
		strcpy(buf, process_name(argument));
		if (buf[0] == '\0') {
			act("$n{x says '{SYou can't string it as that, $N{S.{x'", qm, NULL, ch, TO_VICT);
			return;
		}

		free_string(obj->short_descr);
		obj->short_descr	= str_dup(argument);
		free_string(obj->name);
		obj->name			= str_dup(buf);
	} else if (!str_cmp(item->name, "long")) {
		free_string(obj->description);
		obj->description = str_dup(argument);
	} else {
		send_to_char("BUG!!! Tell an immortal.\r\n", ch);
		printf_debug("restring_item: Invalid type: %s", item->name);
		return;
	}
	deduct_price(ch, item);
	act("$n{x says '{SAll done, $N{S!{x'", qm, NULL, ch, TO_VICT);
}

QITEM_FN_DEF(title_pretitle) {
	if (verb != QVERB_BUY) {
		send_to_char("You can only {Rbuy{x pretitles.\r\n", ch);
		return;
	}

	if (IS_SET (ch->act, PLR_NOTITLE)) {
		act("$n{x says '{SSorry, $N{S, you're not allowed a pretitle.{x'", qm, NULL, ch, TO_VICT);
		return;
	}

	if (!check_price(ch, qm, item))
		return;

	if (argument[0] == '\0') {
		act("$n{x says '{SWell what do you want your pretitle to be, $N{S?{x'", qm, NULL, ch, TO_VICT);
		return;
	}

	char buf[MAX_STRING_LENGTH];
	if (strlen_color(argument) > 10)
		strcpy(buf, end_string(argument, 10));
	else
		strcpy(buf, argument);
	strcat(buf, "{x");

	free_string(ch->pcdata->pretit);
	ch->pcdata->pretit = str_dup(buf);
	deduct_price(ch, item);
	act("$n{x says '{SAll done, $N{S!{x'", qm, NULL, ch, TO_VICT);
}

QITEM_FN_DEF(title_whotitle) {
	if (verb != QVERB_BUY) {
		send_to_char("You can only {Rbuy{x whotitles.\r\n", ch);
		return;
	}

	if (IS_SET (ch->act, PLR_NOTITLE)) {
		act("$n{x says '{SSorry, $N{S, you're not allowed a whotitle.{x'", qm, NULL, ch, TO_VICT);
		return;
	}

	if (!check_price(ch, qm, item))
		return;

	if (argument[0] == '\0') {
		act("$n{x says '{SWell what do you want your whotitle to be, $N{S?{x'", qm, NULL, ch, TO_VICT);
		return;
	}

	char buf[MAX_STRING_LENGTH];
	if (IS_IMMORTAL(ch))
		sprintf(buf, "%s{x", end_string(argument, 16));
	else
		sprintf(buf, "%s{x", end_string(argument, 10));

	free_string(ch->pcdata->who_descr);
	ch->pcdata->who_descr = str_dup(buf);
	deduct_price(ch, item);
	act("$n{x says '{SAll done, $N{S!{x'", qm, NULL, ch, TO_VICT);
}