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