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/
/*
 * Container.cpp
 *   Classes to handle classes that can be containers or contained by a container
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * 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"

//################################################################################
//# Container
//################################################################################

Container::Container() {
    // TODO Auto-generated constructor stub

}


bool Container::purge(bool includePets) {
	bool purgedAll = true;
	purgedAll &= purgeMonsters(includePets);
	purgedAll &= purgeObjects();

	return(purgedAll);
}

bool Container::purgeMonsters(bool includePets) {
	bool purgedAll = true;
	MonsterSet::iterator mIt, prevIt;
	Monster *mons = 0;
	for(mIt = monsters.begin() ; mIt != monsters.end() ; ) {
		prevIt = mIt;
		mons = (*mIt++);
		if(includePets == false && mons->isPet()) {
			purgedAll = false;
			continue;
		}
        if(mons->flagIsSet(M_DM_FOLLOW)) {
            Player* master = mons->getPlayerMaster();
            if(master) {
                master->clearFlag(P_ALIASING);

                master->setAlias(0);
                master->print("%1M's soul was purged.\n", mons);
                master->delPet(mons->getAsMonster());
            }
        }

		monsters.erase(prevIt);
		free_crt(mons);
	}
	return(purgedAll);
}
bool Container::purgeObjects() {
	bool purgedAll = true;
	ObjectSet::iterator oIt, prevIt;
	Object* obj;
	for(oIt = objects.begin() ; oIt != objects.end() ; ) {
		prevIt = oIt;
		obj = (*oIt++);
		if(!obj->flagIsSet(O_TEMP_PERM)) {
			objects.erase(prevIt);
			delete obj;
		} else {
			purgedAll = false;
		}
	}
	return(purgedAll);
}

Container* Container::remove(Containable* toRemove) {
    if(!toRemove)
        return(NULL);

    Object* remObject = dynamic_cast<Object*>(toRemove);
    Player* remPlayer = dynamic_cast<Player*>(toRemove);
    Monster* remMonster = dynamic_cast<Monster*>(toRemove);

    bool toReturn = false;
    if(remObject) {
        objects.erase(remObject);
        toReturn = true;
    } else if(remPlayer) {
        players.erase(remPlayer);
        toReturn = true;
    } else if(remMonster) {
        monsters.erase(remMonster);
        toReturn = true;
    } else {
        std::cout << "Don't know how to remove " << toRemove << std::endl;
        toReturn = false;
    }

    //std::cout << "Removing " << toRemove->getName() << " from " << this->getName() << std::endl;

    if(toReturn) {
    	Container* retVal = toRemove->getParent();
        toRemove->setParent(NULL);
        return(retVal);
    }

    return(NULL);
}

bool Container::add(Containable* toAdd) {
    if(!toAdd)
        return(false);

    Object* addObject = dynamic_cast<Object*>(toAdd);
    Player* addPlayer = dynamic_cast<Player*>(toAdd);
    Monster* addMonster = dynamic_cast<Monster*>(toAdd);

    // If we're adding an object or a monster, we're registered and the item we're adding is not,
    // then register the item
    if((addObject || addMonster) && isRegistered() && !toAdd->isRegistered()) {
    	toAdd->registerMo();
    }


    bool toReturn = false;
    if(addObject) {
        std::pair<ObjectSet::iterator, bool> p = objects.insert(addObject);
        toReturn = p.second;
    } else if(addPlayer) {
        std::pair<PlayerSet::iterator, bool> p = players.insert(addPlayer);
        toReturn = p.second;
    } else if(addMonster) {
        std::pair<MonsterSet::iterator, bool> p = monsters.insert(addMonster);
        toReturn = p.second;
    } else {
        std::cout << "Don't know how to add " << toAdd << std::endl;
        toReturn = false;
    }

    if(toReturn) {
        toAdd->setParent(this);
    }
    //std::cout << "Adding " << toAdd->getName() << " to " << this->getName() << std::endl;
    return(toReturn);
}


void Container::registerContainedItems() {
	// Player registration is handled by the server
	MonsterSet::iterator mIt;
	for(mIt = monsters.begin() ; mIt != monsters.end() ; ) {
		Monster* mons = *mIt++;
		mons->registerMo();
	}
	ObjectSet::iterator oIt;
	for(oIt = objects.begin() ; oIt != objects.end() ; ) {
		Object* obj = *oIt++;
		obj->registerMo();
	}
}
void Container::unRegisterContainedItems() {
	// Player registration is handled by the server
	for(Monster* mons : monsters) {
		mons->unRegisterMo();
	}
	for(Object* obj : objects) {
		obj->unRegisterMo();
	}
}


//*********************************************************************
//						wake
//*********************************************************************

void Container::wake(bstring str, bool noise) const {
    for(Player* ply : players) {
		ply->wake(str, noise);
	}
}

bool Container::checkAntiMagic(Monster* ignore) {
    for(Monster* mons : monsters) {
        if(mons == ignore)
            continue;
        if(mons->flagIsSet(M_ANTI_MAGIC_AURA)) {
            broadcast(NULL,  this, "^B%M glows bright blue.", mons);
            return(true);
        }
    }
    return(false);
}

MudObject* Container::findTarget(const Creature* searcher, const cmd* cmnd, int num) const {
	return(findTarget(searcher, cmnd->str[num], cmnd->val[num]));
}

MudObject* Container::findTarget(const Creature* searcher, const bstring& name, const int num,  bool monFirst, bool firstAggro, bool exactMatch) const {
	int match=0;
	return(findTarget(searcher, name, num, monFirst, firstAggro, exactMatch, match));
}

MudObject* Container::findTarget(const Creature* searcher, const bstring& name, const int num,  bool monFirst, bool firstAggro, bool exactMatch, int& match) const {
	MudObject* toReturn = 0;

	if((toReturn = findCreature(searcher, name, num, monFirst, firstAggro, exactMatch, match))) {
		return(toReturn);
	}
	// TODO: Search the container's objects
	return(toReturn);
}

// Wrapper for the real findObject to support legacy callers
Object* Container::findObject(const Creature *searcher, const cmd* cmnd, int val) const {
	return(findObject(searcher, cmnd->str[val], cmnd->val[val]));
}
Object* Container::findObject(const Creature* searcher, const bstring& name, const int num, bool exactMatch ) const {
	int match = 0;
	return(findObject(searcher, name, num,exactMatch, match));
}
Object* Container::findObject(const Creature* searcher, const bstring& name, const int num, bool exactMatch, int& match) const {
	Object *target = 0;
	for(Object* obj : objects) {
        if(isMatch(searcher, obj, name, exactMatch)) {
            match++;
            if(match == num) {
                if(exactMatch)
                    return(obj);
                else {
                    target = obj;
                    break;
                }

            }
        }
	}

	return(target);
}


// Wrapper for the real findCreature to support legacy callers
Creature* Container::findCreature(const Creature* searcher, const cmd* cmnd, int num) const {
	return(findCreature(searcher, cmnd->str[num], cmnd->val[num]));
}

Creature* Container::findCreaturePython(Creature* searcher, const bstring& name, bool monFirst, bool firstAggro, bool exactMatch ) {
	int ignored=0;
	int num = 1;

	bstring newName = name;
	newName.trim();
	unsigned int sLoc = newName.ReverseFind(" ");
	if(sLoc != bstring::npos) {
		num = newName.right(newName.length() - sLoc).toInt();
		if(num != 0) {
			newName = newName.left(sLoc);
		} else {
			num = 1;
		}
	}

	std::cout << "Looking for '" << newName << "' #" << num << "\n";

	return(findCreature(searcher, newName, num, monFirst, firstAggro, exactMatch, ignored));
}

// Wrapper for the real findCreature for callers that don't care about the value of match
Creature* Container::findCreature(const Creature* searcher, const bstring& name, const int num, bool monFirst, bool firstAggro, bool exactMatch )  const {
	int ignored=0;
	return(findCreature(searcher, name, num, monFirst, firstAggro, exactMatch, ignored));
}
bool isMatch(const Creature* searcher, MudObject* target, const bstring& name, bool exactMatch, bool checkVisibility) {
    if(!target)
        return(false);
    if(checkVisibility && !searcher->canSee(target))
        return(false);

    // ID match is exact, regardless of exactMatch option
    if(target->getId() == name)
    	return(true);

    if(exactMatch) {
        if(target->getName() == name) {
            return(true);
        }

    } else {
    	if(target->isCreature() && keyTxtEqual(target->getAsCreature(), name.c_str())) {
    		return(true);
    	} else if(target->isObject() && keyTxtEqual(target->getAsObject(), name.c_str())) {
            return(true);
        }
    }
    return(false);
}

// The real findCreature, will take and return the value of match as to allow for findTarget to find the 3rd thing named
// gold with a monster name goldfish, player named goldmine, and some gold in the room!
Creature* Container::findCreature(const Creature* searcher, const bstring& name, const int num, bool monFirst, bool firstAggro, bool exactMatch, int& match) const {

	if(!searcher || name.empty())
		return(NULL);

	Creature* target=0;
	for(int i = 1 ; i <= 2 ; i++) {
	    if( (monFirst && i == 1) || (!monFirst && i == 2) ) {
	        target = findMonster(searcher, name, num, firstAggro, exactMatch, match);
	    } else {
	        target = findPlayer(searcher, name, num, exactMatch, match);
	    }

	    if(target) {
	        return(target);
	    }
	}
	return(target);

}

Monster* Container::findMonster(const Creature* searcher, const cmd* cmnd, int num) const {
	return(findMonster(searcher, cmnd->str[num], cmnd->val[num]));
}
Monster* Container::findMonster(const Creature* searcher, const bstring& name, const int num, bool firstAggro, bool exactMatch) const {
    int match = 0;
    return(findMonster(searcher, name, num, firstAggro, exactMatch, match));
}
Monster* Container::findMonster(const Creature* searcher, const bstring& name, const int num, bool firstAggro, bool exactMatch, int& match) const {
    Monster* target = 0;
    for(Monster* mons : searcher->getParent()->monsters) {
        if(isMatch(searcher, mons, name, exactMatch)) {
            match++;
            if(match == num) {
                if(exactMatch)
                    return(mons);
                else {
                    target = mons;
                    break;
                }

            }
        }
    }
    if(firstAggro && target) {
        if(num < 2 && searcher->pFlagIsSet(P_KILL_AGGROS))
            return(getFirstAggro(target, searcher));
        else
            return(target);
    } else  {
        return(target);
    }
}
Player* Container::findPlayer(const Creature* searcher, const cmd* cmnd, int num) const {
	return(findPlayer(searcher, cmnd->str[num], cmnd->val[num]));
}
Player* Container::findPlayer(const Creature* searcher, const bstring& name, const int num, bool exactMatch) const {
    int match = 0;
    return(findPlayer(searcher, name, num, exactMatch, match));
}
Player* Container::findPlayer(const Creature* searcher, const bstring& name, const int num, bool exactMatch, int& match) const {
    for(Player* ply : searcher->getParent()->players) {
        if(isMatch(searcher, ply, name, exactMatch)) {
            match++;
            if(match == num) {
                return(ply);
            }
        }
    }
    return(NULL);
}


//################################################################################
//# Containable
//################################################################################

Containable::Containable() {
    parent = 0;
    lastParent = 0;
}


void Containable::removeFromSet() {
	lastParent = removeFrom();
}
void Containable::addToSet() {
	addTo(lastParent);
	lastParent = 0;
}

bool Containable::addTo(Container* container) {
    if(this->parent != NULL && parent->getAsMudObject() != container->getAsMudObject()) {
        std::cout << "Non Null Parent" << std::endl;
        return(0);
    }

    if(container == NULL)
        return(removeFrom());

    if(this->isCreature()) {
    	if(container->isUniqueRoom()) {
    		getAsCreature()->currentLocation.room = container->getAsUniqueRoom()->info;
    	} else if (container->isAreaRoom()) {
    		getAsCreature()->currentLocation.mapmarker = container->getAsAreaRoom()->mapmarker;
    	}
    }
    return(container->add(this));
}

Container* Containable::removeFrom() {
    if(!parent) {
        return(NULL);
    }

    if(isCreature()) {
    	getAsCreature()->currentLocation.room.clear();
    	getAsCreature()->currentLocation.mapmarker.reset();
    }
    return(parent->remove(this));
}

void Containable::setParent(Container* container) {
    parent = container;
}
Container* Containable::getParent() const {
    return(parent);
}


bool Containable::inRoom() const {
	return(parent && parent->isRoom());
}
bool Containable::inUniqueRoom() const {
	return(parent && parent->isUniqueRoom());
}
bool Containable::inAreaRoom() const {
	return(parent && parent->isAreaRoom());
}
bool Containable::inObject() const {
	return(parent && parent->isObject());
}
bool Containable::inPlayer() const {
	return(parent && parent->isPlayer());
}
bool Containable::inMonster() const {
	return(parent && parent->isMonster());
}
bool Containable::inCreature() const {
	return(parent && parent->isCreature());
}

BaseRoom* Containable::getRoomParent() {
	if(!parent)
		return(NULL);
	return(parent->getAsRoom());
}
UniqueRoom* Containable::getUniqueRoomParent() {
	if(!parent)
			return(NULL);
	return(parent->getAsUniqueRoom());
}
AreaRoom* Containable::getAreaRoomParent() {
	if(!parent)
		return(NULL);
	return(parent->getAsAreaRoom());
}
Object* Containable::getObjectParent() {
	if(!parent)
		return(NULL);
	return(parent->getAsObject());
}
Player* Containable::getPlayerParent() {
	if(!parent)
		return(NULL);
	return(parent->getAsPlayer());
}
Monster* Containable::getMonsterParent() {
	if(!parent)
		return(NULL);
	return(parent->getAsMonster());
}
Creature* Containable::getCreatureParent() {
	if(!parent)
		return(NULL);
	return(parent->getAsCreature());
}

const BaseRoom* Containable::getConstRoomParent() const {
	if(!parent)
		return(NULL);
	return(parent->getAsConstRoom());
}
const UniqueRoom* Containable::getConstUniqueRoomParent() const {
	if(!parent)
		return(NULL);
	return(parent->getAsConstUniqueRoom());
}
const AreaRoom* Containable::getConstAreaRoomParent() const {
	if(!parent)
		return(NULL);
	return(parent->getAsConstAreaRoom());
}
const Object* Containable::getConstObjectParent() const {
	if(!parent)
		return(NULL);
	return(parent->getAsConstObject());
}
const Player* Containable::getConstPlayerParent() const {
	if(!parent)
		return(NULL);
	return(parent->getAsConstPlayer());
}
const Monster* Containable::getConstMonsterParent() const {
	if(!parent)
		return(NULL);
	return(parent->getAsConstMonster());
}

const Creature* Containable::getConstCreatureParent() const {
	if(!parent)
		return(NULL);
	return(parent->getAsConstCreature());
}