2012-02-12 22:09:38 +00:00
|
|
|
/**************************************************************************
|
|
|
|
* File: lists.c Part of tbaMUD *
|
2012-02-19 22:02:25 +00:00
|
|
|
* Usage: Handling of in-game lists *
|
2012-02-12 22:09:38 +00:00
|
|
|
* *
|
2012-02-19 22:02:25 +00:00
|
|
|
* By Vatiken. Copyright 2012 by Joseph Arnusch *
|
2012-02-12 22:09:38 +00:00
|
|
|
**************************************************************************/
|
|
|
|
|
|
|
|
#include "conf.h"
|
|
|
|
#include "sysdep.h"
|
|
|
|
#include "structs.h"
|
|
|
|
#include "utils.h"
|
|
|
|
#include "db.h"
|
|
|
|
#include "dg_event.h"
|
|
|
|
|
2013-02-15 03:54:25 +00:00
|
|
|
static struct iterator_data Iterator;
|
|
|
|
static bool loop = FALSE;
|
|
|
|
static struct list_data *pLastList = NULL;
|
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
/* Global lists */
|
|
|
|
struct list_data * global_lists = NULL;
|
2013-02-15 03:54:25 +00:00
|
|
|
struct list_data * group_list = NULL;
|
2012-02-12 22:09:38 +00:00
|
|
|
|
|
|
|
struct list_data * create_list(void)
|
|
|
|
{
|
|
|
|
struct list_data *pNewList;
|
|
|
|
static bool first_list = TRUE;
|
|
|
|
|
|
|
|
CREATE(pNewList, struct list_data, 1);
|
|
|
|
|
|
|
|
pNewList->pFirstItem = NULL;
|
|
|
|
pNewList->pLastItem = NULL;
|
|
|
|
pNewList->iIterators = 0;
|
|
|
|
pNewList->iSize = 0;
|
|
|
|
|
|
|
|
/* Add to global lists, primarily for debugging purposes */
|
2012-02-19 22:02:25 +00:00
|
|
|
if (first_list == FALSE)
|
2012-02-12 22:09:38 +00:00
|
|
|
add_to_list(pNewList, global_lists);
|
2012-02-19 22:02:25 +00:00
|
|
|
else
|
|
|
|
first_list = FALSE;
|
|
|
|
|
2012-06-19 21:11:14 +00:00
|
|
|
return (pNewList);
|
2012-02-12 22:09:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct item_data * create_item(void)
|
|
|
|
{
|
|
|
|
struct item_data *pNewItem;
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
CREATE(pNewItem, struct item_data, 1);
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
pNewItem->pNextItem = NULL;
|
|
|
|
pNewItem->pPrevItem = NULL;
|
|
|
|
pNewItem->pContent = NULL;
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
return (pNewItem);
|
|
|
|
}
|
|
|
|
|
|
|
|
void free_list(struct list_data * pList)
|
|
|
|
{
|
|
|
|
void * pContent;
|
2012-02-27 01:04:09 +00:00
|
|
|
|
2013-02-15 03:54:25 +00:00
|
|
|
clear_simple_list();
|
2012-02-19 22:02:25 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
if (pList->iSize)
|
2012-02-19 22:02:25 +00:00
|
|
|
while ((pContent = simple_list(pList)))
|
2012-02-12 22:09:38 +00:00
|
|
|
remove_from_list(pContent, pList);
|
|
|
|
|
|
|
|
if (pList->iSize > 0)
|
|
|
|
mudlog(CMP, LVL_GOD, TRUE, "List being freed while not empty.");
|
|
|
|
|
2012-02-19 22:02:25 +00:00
|
|
|
/* Global List for debugging */
|
2012-02-21 06:13:45 +00:00
|
|
|
if (pList != global_lists)
|
|
|
|
remove_from_list(pList, global_lists);
|
2012-02-19 22:02:25 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
free(pList);
|
|
|
|
}
|
|
|
|
|
|
|
|
void add_to_list(void * pContent, struct list_data * pList)
|
|
|
|
{
|
|
|
|
struct item_data * pNewItem;
|
|
|
|
struct item_data * pLastItem;
|
|
|
|
|
|
|
|
/* Allocate our memory */
|
|
|
|
pNewItem = create_item();
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
/* Place the contents in the item */
|
|
|
|
pNewItem->pContent = pContent;
|
|
|
|
pNewItem->pNextItem = NULL;
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
/* If we are the first entry in the list, mark us as such */
|
|
|
|
if (pList->pFirstItem == NULL)
|
|
|
|
pList->pFirstItem = pNewItem;
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
/* Grab our last item from the list and attach it to our new item */
|
|
|
|
if (pList->pLastItem) {
|
|
|
|
pLastItem = pList->pLastItem;
|
|
|
|
pLastItem->pNextItem = pNewItem;
|
|
|
|
pNewItem->pPrevItem = pLastItem;
|
2012-02-19 22:02:25 +00:00
|
|
|
}
|
2012-02-12 22:09:38 +00:00
|
|
|
|
|
|
|
/* Make our new item our last item in the list */
|
|
|
|
pList->pLastItem = pNewItem;
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
pList->iSize++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void remove_from_list(void * pContent, struct list_data * pList)
|
|
|
|
{
|
|
|
|
struct item_data *pRemovedItem;
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
if ((pRemovedItem = find_in_list(pContent, pList)) == NULL) {
|
2012-08-12 18:15:40 +00:00
|
|
|
mudlog(CMP, LVL_GOD, TRUE, "WARNING: Attempting to remove contents that don't exist in list.");
|
2012-02-12 22:09:38 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
if (pRemovedItem == pList->pFirstItem)
|
|
|
|
pList->pFirstItem = pRemovedItem->pNextItem;
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
if (pRemovedItem == pList->pLastItem)
|
|
|
|
pList->pLastItem = pRemovedItem->pPrevItem;
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
if (pRemovedItem->pPrevItem)
|
|
|
|
pRemovedItem->pPrevItem->pNextItem = pRemovedItem->pNextItem;
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
if (pRemovedItem->pNextItem)
|
|
|
|
pRemovedItem->pNextItem->pPrevItem = pRemovedItem->pPrevItem;
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
pList->iSize--;
|
|
|
|
if (pList->iSize == 0) {
|
|
|
|
pList->pFirstItem = NULL;
|
|
|
|
pList->pLastItem = NULL;
|
|
|
|
}
|
2012-06-19 21:11:14 +00:00
|
|
|
free(pRemovedItem);
|
2012-02-12 22:09:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Merges an iterator with a list
|
|
|
|
* @post Don't forget to remove the iterator with remove_iterator().
|
|
|
|
* */
|
|
|
|
|
|
|
|
void * merge_iterator(struct iterator_data * pIterator, struct list_data * pList)
|
|
|
|
{
|
|
|
|
void * pContent;
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
if (pList == NULL) {
|
2012-08-12 18:15:40 +00:00
|
|
|
mudlog(NRM, LVL_GOD, TRUE, "WARNING: Attempting to merge iterator to NULL list.");
|
2012-02-12 22:09:38 +00:00
|
|
|
pIterator->pList = NULL;
|
|
|
|
pIterator->pItem = NULL;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (pList->pFirstItem == NULL) {
|
2012-08-12 18:15:40 +00:00
|
|
|
mudlog(NRM, LVL_GOD, TRUE, "WARNING: Attempting to merge iterator to empty list.");
|
2012-02-12 22:09:38 +00:00
|
|
|
pIterator->pList = NULL;
|
|
|
|
pIterator->pItem = NULL;
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
pList->iIterators++;
|
|
|
|
pIterator->pList = pList;
|
|
|
|
pIterator->pItem = pList->pFirstItem;
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
pContent = pIterator->pItem ? pIterator->pItem->pContent : NULL;
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
return (pContent);
|
|
|
|
}
|
|
|
|
|
|
|
|
void remove_iterator(struct iterator_data * pIterator)
|
|
|
|
{
|
|
|
|
if (pIterator->pList == NULL) {
|
2012-08-12 18:15:40 +00:00
|
|
|
mudlog(NRM, LVL_GOD, TRUE, "WARNING: Attempting to remove iterator from NULL list.");
|
2012-06-19 21:11:14 +00:00
|
|
|
return;
|
2012-02-12 22:09:38 +00:00
|
|
|
}
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
pIterator->pList->iIterators--;
|
|
|
|
pIterator->pList = NULL;
|
|
|
|
pIterator->pItem = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Spits out an item and cycles down the list
|
|
|
|
* @return Returns the content of the list
|
|
|
|
* */
|
|
|
|
|
|
|
|
void * next_in_list(struct iterator_data * pIterator)
|
|
|
|
{
|
|
|
|
void * pContent;
|
|
|
|
struct item_data * pTempItem;
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
if (pIterator->pList == NULL) {
|
2012-08-12 18:15:40 +00:00
|
|
|
mudlog(NRM, LVL_GOD, TRUE, "WARNING: Attempting to get content from iterator with NULL list.");
|
2012-02-12 22:09:38 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
/* Cycle down the list */
|
|
|
|
pTempItem = pIterator->pItem->pNextItem;
|
|
|
|
pIterator->pItem = pTempItem;
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
/* Grab the content */
|
|
|
|
pContent = pIterator->pItem ? pIterator->pItem->pContent : NULL;
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
return (pContent);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Searches through the a list and returns the item block that holds pContent
|
|
|
|
* @return Returns the actual item block and not the pContent itself, since
|
|
|
|
* it is assumed you already have the pContent.
|
|
|
|
* */
|
|
|
|
|
|
|
|
struct item_data * find_in_list(void * pContent, struct list_data * pList)
|
|
|
|
{
|
|
|
|
void * pFoundItem;
|
|
|
|
struct item_data *pItem = NULL;
|
|
|
|
bool found;
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
pFoundItem = merge_iterator(&Iterator, pList);
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
for (found = FALSE; pFoundItem != NULL; pFoundItem = next_in_list(&Iterator)) {
|
|
|
|
if (pFoundItem == pContent) {
|
|
|
|
found = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
if (found)
|
|
|
|
pItem = Iterator.pItem;
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
remove_iterator(&Iterator);
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
if (found)
|
|
|
|
return (pItem);
|
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-02-15 03:54:25 +00:00
|
|
|
void clear_simple_list(void)
|
|
|
|
{
|
|
|
|
loop = FALSE;
|
|
|
|
pLastList = NULL;
|
|
|
|
}
|
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
/** This is the "For Dummies" function, as although it's not as flexible,
|
|
|
|
* it is even easier applied for list searches then using your own iterators
|
|
|
|
* and next_in_list()
|
|
|
|
* @usage Common usage would be as follows:
|
|
|
|
*
|
|
|
|
* while ((var = (struct XXX_data *) simple_list(XXX_list))) {
|
|
|
|
* blah blah....
|
|
|
|
* }
|
|
|
|
* @return Will return the next list content until it hits the end, in which
|
|
|
|
* will detach itself from the list.
|
|
|
|
* */
|
|
|
|
|
|
|
|
void * simple_list(struct list_data * pList)
|
|
|
|
{
|
|
|
|
void * pContent;
|
2012-06-19 21:11:14 +00:00
|
|
|
|
|
|
|
/* Reset List */
|
|
|
|
if (pList == NULL) {
|
2013-02-15 03:54:25 +00:00
|
|
|
clear_simple_list();
|
2012-06-19 21:11:14 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
if (!loop || pLastList != pList) {
|
2012-02-19 22:02:25 +00:00
|
|
|
if (loop && pLastList != pList)
|
2012-02-12 22:09:38 +00:00
|
|
|
mudlog(CMP, LVL_GRGOD, TRUE, "SYSERR: simple_list() forced to reset itself.");
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
pContent = merge_iterator(&Iterator, pList);
|
|
|
|
if (pContent != NULL) {
|
|
|
|
pLastList = pList;
|
|
|
|
loop = TRUE;
|
|
|
|
return (pContent);
|
|
|
|
} else
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((pContent = next_in_list(&Iterator)) != NULL)
|
|
|
|
return (pContent);
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
remove_iterator(&Iterator);
|
|
|
|
loop = FALSE;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void * random_from_list(struct list_data * pList)
|
|
|
|
{
|
|
|
|
void * pFoundItem;
|
|
|
|
bool found;
|
|
|
|
int number;
|
|
|
|
int count = 1;
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
if (pList->iSize <= 0)
|
|
|
|
return NULL;
|
|
|
|
else
|
|
|
|
number = rand_number(1, pList->iSize);
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
pFoundItem = merge_iterator(&Iterator, pList);
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
for (found = FALSE; pFoundItem != NULL; pFoundItem = next_in_list(&Iterator), count++) {
|
|
|
|
if (count == number) {
|
|
|
|
found = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
remove_iterator(&Iterator);
|
2012-06-19 21:11:14 +00:00
|
|
|
|
2012-02-12 22:09:38 +00:00
|
|
|
if (found)
|
|
|
|
return (pFoundItem);
|
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct list_data * randomize_list(struct list_data * pList)
|
|
|
|
{
|
|
|
|
struct list_data * newList;
|
|
|
|
void * pContent;
|
|
|
|
|
|
|
|
if (pList->iSize == 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
newList = create_list();
|
|
|
|
|
|
|
|
while ((pContent = random_from_list(pList)) != NULL) {
|
|
|
|
remove_from_list(pContent, pList);
|
|
|
|
add_to_list(pContent, newList);
|
|
|
|
}
|
|
|
|
|
|
|
|
free_list(pList);
|
|
|
|
|
|
|
|
return (newList);
|
|
|
|
}
|