roh/conf/area/
roh/game/talk/
roh/help/
roh/monsters/ocean/
roh/objects/ocean/
roh/player/
roh/rooms/area/1/
roh/rooms/misc/
roh/rooms/ocean/
roh/src-2.44b/
/*
 * oldQuest.cpp
 *	 Xml parsing and various quest related functions (Including monster interaction)
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * Permission to use, modify and distribute is granted via the
 *  Creative Commons - Attribution - Non Commercial - Share Alike 3.0 License
 *    http://creativecommons.org/licenses/by-nc-sa/3.0/
 *
 * 	Copyright (C) 2007-2009 Jason Mitchell, Randi Mitchell
 * 	   Contributions by Tim Callahan, Jonathan Hseu
 *  Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman
 *
 */
#include "mud.h"
#include "commands.h"
#include "factions.h"
#include "quests.h"
#include "tokenizer.h"

// Function prototypes
static questPtr parseQuest(xmlDocPtr doc, xmlNodePtr cur);

// Loads the quests file
bool Config::loadQuestTable() {
	xmlDocPtr       doc;
	questPtr	    curquest;
	xmlNodePtr      cur;
	char	filename[80];

	// build an XML tree from a the file
	sprintf(filename, "%s/questTable.xml", CONFPATH);
	doc = xml::loadFile(filename, "Quests");
	if(doc == NULL)
		return(false);

	cur = xmlDocGetRootElement(doc);
	numQuests = 0;
	memset(questTable, 0, sizeof(questTable));

	// First level we expect a Quest
	cur = cur->children;
	while(cur && xmlIsBlankNode(cur))
		cur = cur->next;

	if(cur == 0) {
		xmlFreeDoc(doc);
		return(false);
	}

	clearQuestTable();
	// Go through the nodes and grab off all Quests
	while(cur != NULL) {
		if((!strcmp((char *)cur->name, "Quest"))) {
			// Parse the quest
			curquest = parseQuest(doc, cur);
			// If we parsed a valid quest, add it to the table
			if(curquest != NULL)
				questTable[numQuests++] = curquest;
			// No more than 128 quests currently allowed
			if(numQuests >= 128)
				break;
		}
		cur = cur->next;
	}
	xmlFreeDoc(doc);
	xmlCleanupParser();
	return(true);
}

static questPtr parseQuest(xmlDocPtr doc, xmlNodePtr cur) {
	questPtr ret = NULL;
	ret = new quest;
	if(ret == NULL) {
		loge("Quest_Load: out of memory\n");
		return(NULL);
	}

	cur = cur->children;
	// Note: (char *)xmlNodeListGetString returns a string which MUST be freed
	//       thus we can't use atoi...use toInt or toLong

	while(cur != NULL) {
		if((!strcmp((char *)cur->name, "ID")))
			ret->num = xml::toNum<int>((char *)xmlNodeListGetString(doc, cur->children, 1));
		if((!strcmp((char *)cur->name, "name")))
			ret->name = (char *)xmlNodeListGetString(doc, cur->children, 1);
		if((!strcmp((char *)cur->name, "exp")))
			ret->exp = xml::toNum<int>((char *)xmlNodeListGetString(doc, cur->children, 1));
		cur = cur->next;
	}

	return (ret);
}


// Free the memory being used by the quest table
void Config::clearQuestTable() {
	int i;
	for(i=0;i<numQuests;i++)
		freeQuest(questTable[i]);
}

// Free the memory being used by a quest
void freeQuest(questPtr toFree) {
	if(toFree->name)
		free(toFree->name);
	delete toFree;
}

void fulfillQuest(Player* player, Object* object) {
	if(object->getQuestnum()) {
		player->print("Quest fulfilled!");
		if(object->getType() != MONEY) {
			player->printColor(" Don't drop %P.\n", object);
			player->print("You won't be able to pick it up again.");
		}
		player->print("\n");
		player->setQuest(object->getQuestnum()-1);
		player->addExperience(get_quest_exp(object->getQuestnum()));
		if(!player->halftolevel())
			player->print("%ld experience granted.\n", get_quest_exp(object->getQuestnum()));
	}

	otag	*cop = object->first_obj;
	while(cop) {
		fulfillQuest(player, cop->obj);
		cop = cop->next_tag;
	}
}




//
//
////*********************************************************************
////						cmdTalk
////*********************************************************************
//// This function allows players to speak with monsters if the monster
//// has a talk string set.
//
//int cmdTalk(Player* player, cmd* cmnd) {
//	Monster *target=0;
//	ttag	*tp=0;
//
//	ttag*	t=0;
//	bstring talk;
//
//	player->clearFlag(P_AFK);
//
//	if(!player->ableToDoCommand())
//		return(0);
//
//	if(cmnd->num < 2) {
//		player->print("Talk to whom?\n");
//		return(0);
//	}
//
//	target = player->getRoom()->findMonster(player, cmnd);
//	if(!target) {
//		player->print("You don't see that here.\n");
//		return(0);
//	}
//
//	player->unhide();
//	if(player->checkForSpam())
//		return(0);
//
//	if(target->flagIsSet(M_AGGRESSIVE_AFTER_TALK))
//		target->addEnmCrt(player);
//
//	if(	target->current_language &&
//		!target->languageIsKnown(player->current_language) &&
//		!player->checkStaff("%M doesn't seem to understand anything in %s.\n", target, get_language_adj(player->current_language))
//	)
//		return(0);
//
//	if(	!target->canSpeak() &&
//		!player->checkStaff("%M is unable to speak right now.\n", target)
//	)
//		return(0);
//
//	if(	target->talk != "" &&
//		!Faction::willSpeakWith(player, target->getPrimeFaction()) &&
//		!player->checkStaff("%M refuses to speak with you.\n", target)
//	)
//		return(0);
//
//	if(cmnd->num == 2 || !target->flagIsSet(M_TALKS)) {
//		talk = target->talk;
//		if(talk != "")
//			broadcast(player->getSock(), player->getRoom(), "%M speaks to %N in %s.",
//				player, target, get_language_adj(player->current_language));
//	} else {
//		if(!target->first_tlk && !loadCreature_tlk(target)) {
//			broadcast(NULL, player->getRoom(), "%M shrugs.", target);
//			return(PROMPT);
//		}
//
//		broadcast_rom_LangWc(NORMAL, get_lang_color(target->current_language),
//			target->current_language, fd, player->area_room, player->room, "%M asks %N about \"%s\".",
//			player, target, cmnd->str[2]);
//
//		tp = target->first_tlk;
//		while(tp && !t) {
//			if(!strcmp(cmnd->str[2], tp->key)) {
//				t = tp;
//				talk = tp->response;
//			}
//			tp = tp->next_tag;
//		}
//		if(!t) {
//			broadcast(NULL, player->getRoom(), "%M shrugs.", target);
//			return(0);
//		}
//	}
//
//
//	if(talk != "") {
//		broadcast_rom_LangWc(NORMAL, get_lang_color(target->current_language),
//			target->current_language, fd, player->area_room, player->room,
//			"%M says to %N, \"%s\"", target, player, talk.c_str());
//		printForeignTongueMsg(player->getRoom(), target);
//
//		ANSI(fd, get_lang_color(target->current_language));
//		player->printColor("%M says to you, \"%s\"\n", target, talk.c_str());
//
//		if(t)
//			talk_action(player, target, t);
//	} else
//		broadcast(NULL, player->getRoom(), "%M doesn't say anything.", target);
//
//	return(0);
//}
//
////*********************************************************************
////						talk_action
////*********************************************************************
//// The talk_action function handles a monster's actin when a
//// player asks the monster about a key word. The format for the
//// is defined in the monster's talk file. Currently a monster
//// can attack, or cast spells on the player who mentions the key
//// word or preform any of the defined social commands
//
//void talk_action(Player* player, Monster *target, ttag *tt ) {
//	Object	*object=0;
//	cmd 	cm;
//	int		i=0, n=0, splno=0, reqMp=0, fd = player->fd;
//	int		(*fn)(Creature *, cmd *, int);
//	//unsigned int pos=0;
//	//bstring text = "";
//
//	for(i=0; i<COMMANDMAX; i++) {
//		cm.str[i][0] = 0;
//		cm.str[i][24] = 0;
//		cm.val[i] = 0;
//	}
//	cm.fullstr[0] = 0;
//	cm.num = 0;
//
//	switch(tt->type) {
//	// attack
//	case 1:
//		target->addEnmCrt(player);
//		broadcast(player->getSock(), player->getRoom(), "%M attacks %N\n", target, player);
//		oldPrint(fd, "%M attacks you.\n", target);
//		break;
//
//	// action command
//	case 2:
//		//if(tt->action) {
//			// comes in the format of "keyword ACTION -------"
//
//			strncpy(cm.fullstr, tt->action, 100);
//
//			if(tt->target && !strcmp(tt->target, "PLAYER")) {
//				strcat(cm.fullstr, " ");
//				strcat(cm.fullstr, player->name);
//			}
//
//			stripBadChars(cm.fullstr); // removes '.' and '/'
//			lowercize(cm.fullstr, 0);
//			parse(cm.fullstr, &cm);
//
//			cmdProcess(target, &cm);
//		//}
//		break;
//	// cast
//	case 3:
//		if(tt->action) {
//			strcpy(cm.str[0], "cast");
//			strncpy(cm.str[1], tt->action,25);
//			strcpy(cm.str[2], player->name);
//			cm.val[0] = cm.val[1] = cm.val[2] = 1;
//			cm.num = 3;
//			sprintf(cm.fullstr, "cast %s %s", tt->action, player->name);
//
//			i = 0;
//			do {
//				if(!strcmp(tt->action, get_spell_name(i))) {
//					splno = i;
//					break;
//				}
//				i++;
//			} while(get_spell_num(i) != -1);
//
//			if(splno == -1)
//				return;
//			reqMp = doMpCheck(target, splno);
//			if(!reqMp)
//				return;
//			fn = get_spell_function(splno);
//
//			if((int(*)(Creature *, cmd*, int, char*, osp_t*))fn == splOffensive) {
//				for(i=0; ospell[i].splno != get_spell_num(splno); i++)
//					if(ospell[i].splno == -1)
//						return;
//				n = ((int(*)(Creature *, cmd*, int, const char*, osp_t*))*fn)(target, &cm, CAST, get_spell_name(splno),
//				      &ospell[i]);
//			} else if(target->isEnmCrt(player->name)) {
//				player->print("%M refuses to cast any spells on you.\n", target);
//				return;
//			} else
//				n = ((int(*)(Creature *, cmd*, int))*fn)(target, &cm, CAST);
//
//			if(!n)
//				player->print("%M apologizes that %s cannot currently cast that spell on you.\n",
//					target, target->heShe());
//			// If reqMp is valid, subtract the mp here
//			else if(reqMp != -1)
//				target->subMp(reqMp);
//
//		}
//		break;
//	case 4:
//		i = atoi(tt->action);
//		if(i > 0) {
//			if(loadObject(i, &object)) {
//				if(object->flagIsSet(O_RANDOM_ENCHANT))
//					object->randomEnchant();
//
//				if(	(player->getWeight() + object->getActualWeight() > player->maxWeight()) &&
//					!player->checkStaff("You can't hold anymore.\n") )
//					break;
//
//				if(	object->questnum &&
//					player->questIsSet(object->questnum) &&
//					!player->checkStaff("You may not get that. You have already fulfilled that quest.\n") )
//					break;
//
//				fulfillQuest(player, object);
//
//				player->addObj(object);
//				player->printColor("%M gives you %P\n", target, object);
//				broadcast(player->getSock(), player->getRoom(), "%M gives %N %P\n", target, player, object);
//			} else
//				player->print("%M has nothing to give you.\n", target);
//		}
//		break;
//	default:
//		break;
//	}
//}