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/
/* 
 * queue.c
 *   Deals with the monster, object, and room queues
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___ 
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * 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 "xml.h"


//*********************************************************************
//						flushRoom
//*********************************************************************
// This function flushes out the room queue and clears the room sparse
// pointer array, without saving anything to file. It also clears all
// memory used by loaded rooms. Call this function before leaving the
// program.

void Config::flushRoom() {
	qtag *qt=0;

	while(1) {
		pullQueue(&qt, &roomHead, &roomTail);
		if(!qt)
			break;
		delete roomQueue[qt->str].rom;
		roomQueue.erase(qt->str);
		delete qt;
	}
}

//*********************************************************************
//						flushMonster
//*********************************************************************
// This function flushes out the monster queue and clears the monster
// sparse pointer array without saving anything to file. It also
// clears all memory used by loaded creatures. Call this function
// before leaving the program.

void Config::flushMonster() {
	qtag *qt=0;

	while(1) {
		pullQueue(&qt, &monsterHead, &monsterTail);
		if(!qt)
			break;
		free_crt(monsterQueue[qt->str].mob);
		monsterQueue.erase(qt->str);
		delete qt;
	}
}

//********************************************************************
//						flushObject
//********************************************************************
// This function flushes out the object queue and clears the object
// sparse pointer array without saving anything to file. It also
// clears all memory used by loaded objects. Call this function
// leaving the program.

void Config::flushObject() {
	qtag *qt=0;

	while(1) {
		pullQueue(&qt, &objectHead, &objectTail);
		if(!qt)
			break;
		delete objectQueue[qt->str].obj;
		objectQueue.erase(qt->str);
		delete qt;
	}
}

//*********************************************************************
//						putQueue
//*********************************************************************
// putQueue places the queue tag pointed to by the first paramater onto
// a queue whose head and tail tag pointers are the second and third
// parameters.  If parameters 2 & 3 are 0, then a new queue is created.
// The fourth parameter points to a queue size counter which is
// incremented.	

void Config::putQueue(qtag **qt, qtag **headptr, qtag **tailptr) {
	if(!*headptr) {
		*headptr = *qt;
		*tailptr = *qt;
		(*qt)->next = 0;
		(*qt)->prev = 0;
	} else {
		(*headptr)->prev = *qt;
		(*qt)->next = *headptr;
		(*qt)->prev = 0;
		*headptr = *qt;
	}
}

//*********************************************************************
//						pullQueue
//*********************************************************************
// pullQueue removes the last queue tag on the queue specified by the
// second and third parameters and returns that tag in the first
// parameter.  The fourth parameter points to a queue size counter
// which is decremented.

void Config::pullQueue(qtag **qt, qtag **headptr, qtag **tailptr) {
	if(!*tailptr)
		*qt = 0;
	else {
		*qt = *tailptr;
		if((*qt)->prev) {
			(*qt)->prev->next = 0;
			*tailptr = (*qt)->prev;
		} else {
			*headptr = 0;
			*tailptr = 0;
		}
	}
}

//*********************************************************************
//						delQueue
//*********************************************************************

void Config::delQueue(qtag **qt, qtag **headptr, qtag **tailptr) {
	if((*qt)->prev) {
		((*qt)->prev)->next = (*qt)->next;
		if(*qt == *tailptr)
			*tailptr = (*qt)->prev;
	}
	if((*qt)->next) {
		((*qt)->next)->prev = (*qt)->prev;
		if(*qt == *headptr)
			*headptr = (*qt)->next;
	}
	if(!(*qt)->prev && !(*qt)->next) {
		*headptr = 0;
		*tailptr = 0;
	}
	(*qt)->next = 0;
	(*qt)->prev = 0;
}

//*********************************************************************
//						frontQueue
//*********************************************************************
// frontQueue removes the queue tag pointed to by the first parameter
// from the queue (specified by the second and third parameters) and 
// places it back at the head of the queue.  The fourth parameter is a 
// pointer to a queue size counter, and it remains unchanged.

void Config::frontQueue(qtag **qt, qtag **headptr, qtag **tailptr) {
	delQueue(qt, headptr, tailptr);
	putQueue(qt, headptr, tailptr);
}


//*********************************************************************
//						monsterInQueue
//*********************************************************************

bool Config::monsterInQueue(const CatRef cr) {
	return(monsterQueue.find(cr.str()) != monsterQueue.end());
}

//**********************************************************************
//						frontMonsterQueue
//**********************************************************************

void Config::frontMonsterQueue(const CatRef cr) {
	frontQueue(&monsterQueue[cr.str()].q_mob, &monsterHead, &monsterTail);
}

//**********************************************************************
//						addMonsterQueue
//**********************************************************************

void Config::addMonsterQueue(const CatRef cr, Monster** pMonster) {
	qtag	*qt;

	if(monsterInQueue(cr))
		return;

	qt = new qtag;
	if(!qt)
		merror("addMonsterQueue", FATAL);
	qt->str = cr.str();
	monsterQueue[qt->str].mob = new Monster;
	*monsterQueue[qt->str].mob = **pMonster;
	monsterQueue[qt->str].q_mob = qt;
	putQueue(&qt, &monsterHead, &monsterTail);

	while(monsterQueue.size() > MQMAX) {
		pullQueue(&qt, &monsterHead, &monsterTail);
		free_crt(monsterQueue[qt->str].mob);
		monsterQueue.erase(qt->str);
		delete qt;
	}
}

//**********************************************************************
//						getMonsterQueue
//**********************************************************************

void Config::getMonsterQueue(const CatRef cr, Monster** pMonster) {
	**pMonster = *monsterQueue[cr.str()].mob;
}

//**********************************************************************
//						objectInQueue
//**********************************************************************

bool Config::objectInQueue(const CatRef cr) {
	return(objectQueue.find(cr.str()) != objectQueue.end());
}

//**********************************************************************
//						frontObjectQueue
//**********************************************************************

void Config::frontObjectQueue(const CatRef cr) {
	frontQueue(&objectQueue[cr.str()].q_obj, &objectHead, &objectTail);
}

//**********************************************************************
//						addObjectQueue
//**********************************************************************

void Config::addObjectQueue(const CatRef cr, Object** pObject) {
	qtag	*qt;
	
	if(objectInQueue(cr))
		return;
	
	qt = new qtag;
	if(!qt)
		merror("addObjectQueue", FATAL);
	qt->str = cr.str();
	objectQueue[qt->str].obj = new Object;
	*objectQueue[qt->str].obj = **pObject;
	objectQueue[qt->str].q_obj = qt;
	putQueue(&qt, &objectHead, &objectTail);
	
	while(objectQueue.size() > OQMAX) {
		pullQueue(&qt, &objectHead, &objectTail);
		delete objectQueue[qt->str].obj;
		objectQueue.erase(qt->str);
		delete qt;
	}
}

//**********************************************************************
//						getObjectQueue
//**********************************************************************

void Config::getObjectQueue(const CatRef cr, Object** pObject) {
	**pObject = *objectQueue[cr.str()].obj;
}

//**********************************************************************
//						roomInQueue
//**********************************************************************

bool Config::roomInQueue(const CatRef cr) {
	return(roomQueue.find(cr.str()) != roomQueue.end());
}

//**********************************************************************
//						frontRoomQueue
//**********************************************************************

void Config::frontRoomQueue(const CatRef cr) {
	frontQueue(&roomQueue[cr.str()].q_rom, &roomHead, &roomTail);
}

//**********************************************************************
//						addRoomQueue
//**********************************************************************

void Config::addRoomQueue(const CatRef cr, UniqueRoom** pRoom) {
	qtag	*qt;

	if(roomInQueue(cr))
		return;

	qt = new qtag;
	if(!qt)
		merror("addRoomQueue", FATAL);
	qt->str = cr.str();
	roomQueue[qt->str].rom = *pRoom;
	roomQueue[qt->str].q_rom = qt;
	putQueue(&qt, &roomHead, &roomTail);

	while(roomQueue.size() > RQMAX) {
		pullQueue(&qt, &roomHead, &roomTail);
		if(!roomQueue[qt->str].rom->players.empty()) {
			putQueue(&qt, &roomHead, &roomTail);
			continue;
		}
		if(!roomQueue[qt->str].rom)
			merror("ERROR - loadRoom", NONFATAL);
		// Save Room
		roomQueue[qt->str].rom->saveToFile(PERMONLY);
		delete roomQueue[qt->str].rom;
		roomQueue.erase(qt->str);
		delete qt;
	}
}

//**********************************************************************
//						delRoomQueue
//**********************************************************************

void Config::delRoomQueue(const CatRef cr) {
	if(!roomInQueue(cr))
		return;

	qtag	*qt = roomQueue[cr.str()].q_rom;
	delQueue(&qt, &roomHead, &roomTail);
	delete qt;
	roomQueue.erase(cr.str());
}

//**********************************************************************
//						getRoomQueue
//**********************************************************************

void Config::getRoomQueue(const CatRef cr, UniqueRoom** pRoom) {
	*pRoom = roomQueue[cr.str()].rom;
}

//**********************************************************************
//						queue size
//**********************************************************************

int Config::roomQueueSize() {
	return(roomQueue.size());
}
int Config::monsterQueueSize() {
	return(monsterQueue.size());
}
int Config::objectQueueSize() {
	return(objectQueue.size());
}

//*********************************************************************
//						killMortalObjects
//*********************************************************************
// called on sunrise - runs through active room list and kills darkmetal
// called when a unique group is full - destroys any extra unique items
// in game that can't be kept around anymore

void Config::killMortalObjects() {
	std::list<Area*>::iterator it;
	std::map<bstring, AreaRoom*>::iterator rt;
	std::list<AreaRoom*> toDelete;
	Area	*area=0;
	AreaRoom* room=0;
	qtag 	*qt=0;

	qt = roomHead;
	while(qt) {
		if(roomQueue[qt->str].rom)
			roomQueue[qt->str].rom->killMortalObjects();
		qt = qt->next;
	}

	for(it = gConfig->areas.begin() ; it != gConfig->areas.end() ; it++) {
		area = (*it);
		for(rt = area->rooms.begin() ; rt != area->rooms.end() ; rt++) {
			room = (*rt).second;
			room->killMortalObjects();

			if(room->canDelete())
				toDelete.push_back(room);
		}

		while(!toDelete.empty()) {
			area->remove(toDelete.front());
			toDelete.pop_front();
		}
		toDelete.clear();
	}
}