/*
* 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;
// }
//}