roh/conf.old/area/
roh/config/code/python/
roh/config/game/area/
roh/config/game/signs/
roh/help/dmhelp/
roh/help/help/
roh/log/
roh/log/staff/
roh/monsters/ocean/
roh/objects/misc/
roh/objects/ocean/
roh/player/
roh/rooms/area/1/
roh/rooms/misc/
roh/rooms/ocean/
roh/src-2.47e/
/*
 * Songs.cpp
 *	 Additional song-casting routines.
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * 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-2012 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 "effects.h"
#include "songs.h"

//*********************************************************************
//						Song
//*********************************************************************

Song::Song(xmlNodePtr rootNode) {
	xmlNodePtr curNode = rootNode->children;
	priority = 100;
	delay = 5;
	duration = 15;

	while(curNode) {
			 if(NODE_NAME(curNode, "Name")) { 
                 xml::copyToBString(name, curNode);
                 parseName();
             }
		else if(NODE_NAME(curNode, "Script")) xml::copyToBString(script, curNode);
		else if(NODE_NAME(curNode, "Effect")) xml::copyToBString(effect, curNode);
		else if(NODE_NAME(curNode, "Type")) xml::copyToBString(type, curNode);
		else if(NODE_NAME(curNode, "TargetType")) xml::copyToBString(targetType, curNode);
		else if(NODE_NAME(curNode, "Priority")) xml::copyToNum(priority, curNode);
		else if(NODE_NAME(curNode, "Description")) xml::copyToBString(description, curNode);
		else if(NODE_NAME(curNode, "Delay")) xml::copyToNum(delay, curNode);
		else if(NODE_NAME(curNode, "Duration")) xml::copyToNum(duration, curNode);

		curNode = curNode->next;
	}
}


//*********************************************************************
//						save
//*********************************************************************

void Song::save(xmlNodePtr rootNode) const {
	xml::saveNonNullString(rootNode, "Name", name);
	xml::saveNonNullString(rootNode, "Script", script);
	xml::saveNonNullString(rootNode, "Effect", effect);
	xml::saveNonNullString(rootNode, "Type", type);
	xml::saveNonNullString(rootNode, "TargetType", targetType);
	xml::saveNonZeroNum<int>(rootNode, "Priority", priority);
	xml::saveNonNullString(rootNode,"Description", description);
	xml::saveNonZeroNum<int>(rootNode, "Delay", priority);
	xml::saveNonZeroNum<int>(rootNode, "Duration", priority);

}

//*********************************************************************
//						getEffect
//*********************************************************************

const bstring& Song::getEffect() const {
	return(effect);
}

//*********************************************************************
//						getType
//*********************************************************************

const bstring& Song::getType() const {
	return(type);
}

//*********************************************************************
//						getTargetType
//*********************************************************************

const bstring& Song::getTargetType() const {
	return(targetType);
}

//*********************************************************************
//						runScript
//*********************************************************************

bool Song::runScript(MudObject* singer, MudObject* target) {

	if(script.empty())
		return(false);

	try {
		object localNamespace( (handle<>(PyDict_New())));

		object effectModule( (handle<>(PyImport_ImportModule("songLib"))) );
		localNamespace["songLib"] = effectModule;

		localNamespace["song"] = ptr(this);

		// Default retVal is true
		localNamespace["retVal"] = true;
		addMudObjectToDictionary(localNamespace, "actor", singer);
		addMudObjectToDictionary(localNamespace, "target", target);

		gServer->runPython(script, localNamespace);

		bool retVal = extract<bool>(localNamespace["retVal"]);
		return(retVal);
	}
	catch( error_already_set) {
		gServer->handlePythonError();
	}

	return(false);
}

//*********************************************************************
//						clearSongs
//*********************************************************************

void Config::clearSongs() {

	// TODO: Loop through all players and stop any songs being played
    for(PlayerMap::value_type p : gServer->players) {
        p.second->stopPlaying(true);
    }
	for(std::pair<bstring, Song*> sp : songs) {
		delete sp.second;
	}
	songs.clear();
}

//*********************************************************************
//						isPlaying
//*********************************************************************

bool Creature::isPlaying() {
	return(playing != NULL);
}

//*********************************************************************
//						getPlaying
//*********************************************************************

Song* Creature::getPlaying() {
	return(playing);
}

//*********************************************************************
//						setPlaying
//*********************************************************************

bool Creature::setPlaying(Song* newSong, bool echo) {
	bool wasPlaying = false;
	if(isPlaying()) {
 		stopPlaying(echo);
		wasPlaying = true;
	}

	playing = newSong;

	return(wasPlaying);
}

//*********************************************************************
//						stopPlaying
//*********************************************************************

bool Creature::stopPlaying(bool echo) {
	if(!isPlaying())
		return(false);

	if(echo) {
		print("You stop playing \"%s\"\n", getPlaying()->getName().c_str());
		getRoomParent()->print(getSock(), "%M stops playing %s\n", this, getPlaying()->getName().c_str());
	}
	playing = NULL;
	return(true);
}

//*********************************************************************
//						pulseSong
//*********************************************************************

bool Creature::pulseSong(long t) {
	if(!isPlaying())
		return(false);

	if(getLTLeft(LT_SONG_PLAYED, t))
		return(false);

	if(!playing)
		return(false);

	print("Pulsing song: %s\n", playing->getName().c_str());

	bstring targetType = playing->getTargetType();

	if(playing->getType().equals("effect", false)) {
		// Group effects affect the singer as well
		if(targetType.equals("self",false) || targetType.equals("group", false)) {
			addEffect(playing->getEffect(), -2, -2, this)->setDuration(playing->getDuration());
		}
		if(targetType.equals("group", false) && (getGroup() != NULL)) {
			Group* group = getGroup();
			for(Creature* crt : group->members) {
				if(inSameRoom(crt))
					crt->addEffect(playing->getEffect(), -2, -2, this)->setDuration(playing->getDuration());
			}
		}
		if(targetType.equals("room", false)) {
		    for(Player* ply : getRoomParent()->players) {
				if(getAsPlayer() && ply->getAsPlayer() && getAsPlayer()->isDueling(ply->getName()))
					continue;
				ply->addEffect(playing->getEffect(), -2, -2, this)->setDuration(playing->getDuration());
			}
		}
	} else if(playing->getType() == "script") {
		print("Running script for song \"%s\"\n", playing->getName().c_str());
		MudObject *target = NULL;

		// Find the target here, if any
		if(targetType.equals("target", false)) {
			if(hasAttackableTarget())
				target = getTarget();
		}

		playing->runScript(this, target);
	}


	setLastTime(LT_SONG_PLAYED, t, playing->getDelay());
	return(true);
}


//*********************************************************************
//						dmSongList
//*********************************************************************

int dmSongList(Player* player, cmd* cmnd) {
	const Song* song=0;

	player->printColor("^YSongs\n");
	for(std::pair<bstring, Song*> sp : gConfig->songs) {
		song = sp.second;
		player->printColor("  %s   %d - %s\n	Script: ^y%s^x\n", song->name.c_str(),
			song->priority, song->description.c_str(), song->script.c_str());
	}

	return(0);
}

//*********************************************************************
//						cmdPlay
//*********************************************************************

int cmdPlay(Player* player, cmd* cmnd) {

	if(cmnd->num == 1) {
		if(player->isPlaying()) {
			player->stopPlaying();
			return(0);
		} else {
			player->print("What song would you like to play?\n");
			return(0);
		}
	}

	int retVal = 0;
	Song* song = gConfig->getSong(cmnd->str[1], retVal);

	if(retVal == CMD_NOT_FOUND) {
		player->print("Alas, there exists no song by that name.\n");
		return(0);
	} else if(retVal == CMD_NOT_UNIQUE ) {
		player->print("Alas, there exists many songs by that name, please be more specific!\n");
		return(0);
	}


	if(!song) {
		player->print("Error loading song \"%s\"\n", cmnd->str[1]);
		return(0);
	}


	player->print("Found song: \"%s\"\n", song->getName().c_str());

	// Is there a required instrument? Do we have it?

	// Do certain instruments give a bonus or penalty to this song? Modify it here
	if(!player->isPlaying() || player->getPlaying() != song)
		player->setPlaying(song);

	player->print("You start playing \"%s\"\n", song->getName().c_str());
	player->getRoomParent()->print(player->getSock(), "%M starts playing %s\n", player, song->getName().c_str());

	return(0);
}

//*********************************************************************
//						getDelay
//*********************************************************************

int Song::getDelay() {
	return(delay);
}

//*********************************************************************
//						getDuration
//*********************************************************************

int Song::getDuration() {
	return(duration);
}