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