/
backup/a/
color/
doc/mudprogs/
gods/
player/a/
// VERS 1.1
///* new.bit.c -- infinite bitmask system                      *///
// This is Runter's system for infinite bits. It was made for use
// in Feltain (feltain.org 7777). I, Runter, require no credit, no
// help file documentation of your use, and no email confirmation.
// The only thing I do ask is if you find a bug or have a major change
// that makes the system more efficient or more intelligent than 
// let me know about it. Just remember what goes around comes around.
// We all benifit when we work together.
//
// To successfully use this you will use the variable BITMASK
// "BITMASK act;"
// instead of int in your struct declarations for your bitmasks.
// On this new variable type just pass the variables address to
// the new functions-- set_bit, remove_bit, is_set.
// example: if(is_set(&ch->act, ACT_NPC))
//
// This system passes normal numbers as the bits so you'll need
// to redeclare stuff as you are passing it. 
//
// if(is_set(&ch->act, 400)) // is the 400th bit set?
//
// A good way to change your entire system over would be to redo
// your definitions of A B C D E... aa bb cc and such from defines
// to one enum struct.
// 
// Another important note is that you need to use the new loading
// and saving functions provided when saving your bitmasks. It
// saves them to a single line and loads them from a single line.
//
// Technical note: This system will only use memory required for the
// size of your bitmask. It allocates memory as needed only. This does
// use malloc() and free(). Some servers have memory management systems
// in with their own functions. Feel free to change it how you see fit.
// If you need any more help installing the system you can find me at
// feltain.org 7777 or aim me at jeffreybasurto.

// VERS 2
// In version 2 it still maintains the above functionality with fixes
// but also lets you serialize your bitmask to an array of values
// as well as free and initilize it easily. 
// 
// I use this system as a high level solution to linked lists and have
// used it for my char_list, obj_list, and other places. It is 
// efficient enough to do this and actually saves you managing linked 
// lists and next pointers of ANY kind. It can be adapted for room lists
// for objects and players or global lists. This is an abstract data
// type and you can NOT use this as a queue. Ie, the order you set it
// in will not be the order it comes out serialized. It will sort the
// serialization in no particular way like a linked list does. 
//
// This system also allows you to use qsort out of the box after calling
// serialize_bitmask(). 
//
// After getting your array after calling serialize_bitmask() you will have
// to loop through it to get what is in the list and it will be NUL
// terminated like a string. It can be of any size so don't assume, please.
//
// Report any bugs or additions you have made please!! Any praise is 
// appreciated as well. ^_- I spent a lot of intellectual time trying
// to think of a good implementation of this.
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "mud.h"
/* This struct stuff goes in your global.h -- usually
 * merc.h or mud.h
 *************************************************

 typedef struct bmlist BMlist;
 struct bmlist {
     BMlist *next;
     long set;
     long tar_mask;
 };

 typedef struct bitmask {
     long bits; // number of bits set in total.
     long masks; // number of masks in all.
     BMlist *int_list;
 } BITMASK;

 *************************************************/
// returns false if no removal. True if so.
int REMOVE_BIT(BITMASK *mask, short bit) {
    BMlist *pBlist, *last = 0;


    if (!is_set(mask, bit)) // nothing doing. It isn't set.
        return FALSE;
    --bit;
    // loop through each bitmask we have allocated
    for(pBlist = mask->int_list;pBlist;pBlist = pBlist->next) {
        if (pBlist->set == bit / 32) {// Is this the correct set?
            pBlist->tar_mask &= ~(1 << (bit % 32)); // remove it.
            --mask->bits;
            if (pBlist->tar_mask == 0) {
                if (last)
                    last->next = pBlist->next;
                else
                    mask->int_list = pBlist->next;
                free(pBlist);
                --mask->masks;
            }
            return TRUE;
        }
        last = pBlist;
    }

    return FALSE; // a bug happened. Wee. Somehow.
}

// returns true if a bit was set. Returns 2 if had to allocate. 
// False if already set.
int SET_BIT(BITMASK *mask, short bit) {
    BMlist *pBlist;

    --bit;

    // loop through each bitmask we have already allocated.
    for(pBlist = mask->int_list;pBlist;pBlist = pBlist->next) {
        if (pBlist->set == bit / 32) { // Is this the correct set?
            if (pBlist->tar_mask & (1 << (bit % 32)))
                return FALSE; // Already set.

            pBlist->tar_mask |= 1 << (bit % 32); // Set our bit inside the mask.
            ++mask->bits;
            return 1; // return true with no allocation
        }
    }

    // Not found but not set. We have to allocate and add to the list.
    pBlist = malloc(sizeof(BMlist));
    ++mask->masks;
    pBlist->next = mask->int_list;
    mask->int_list = pBlist;
    pBlist->tar_mask = 0;
    pBlist->set = bit / 32;
    pBlist->tar_mask |= 1 << (bit % 32); // set our bit on new mask
    ++mask->bits;
    return 2; // return true with allocation
}

bool IS_SET(BITMASK *mask, short bit) {
    BMlist *pBlist;

    --bit;

    for(pBlist = mask->int_list;pBlist;pBlist = pBlist->next)
        if (pBlist->set == bit / 32) {
            if (pBlist->tar_mask & 1 << (bit % 32))
                return TRUE;
            else
                return FALSE;
        }

    return FALSE;
}

// Let's serialize this and return all bits that are set in a dynamic list.
// This is useful when you just want to know what to traverse in a bitmask.
// Good for high level solutions to lists of pointers! This is a high level
// solution that *does not* maintain an ordered queue for specific BFS or
// DFS algorithms. This is for algorithms that do not matter.
int *serialize_bitmask(BITMASK *mask) {
    BMlist *pBlist;
    int *ilist = malloc(sizeof(int) * mask->bits + 1), i = 0, z;
    ilist[mask->bits] = 0; // zero terminates it. 0th bit CAN NOT BE SET.

    for(pBlist = mask->int_list;pBlist;pBlist = pBlist->next) {
        for(z = 0;z < 32;++z) {
            if (i > mask->bits) {
                // more found than we have allocated. Maybe residual.
                // May add a check before setting ilist to make sure it
                // doesn't over run but this should be fine. Just don't
                // bug it here for sure. It may not be an error at this
                // point. If you do decide to error check this better
                // this break should be replaced to let it go through.
                break;
            }

            if (pBlist->tar_mask & 1 << z)
                ilist[i++] = pBlist->set * 32 + z + 1;
        }
    }
    if (i < mask->bits + 1) {
        // error. We have less recorded bits than we allocated.
    }
    // This must be freed somewhere with free(ilist) or it will leak.
    // Using a static buffer here would be a poor idea. Using temporary
    // memory allocation would be a good one. Too bad there isn't an
    // ANSI thing for that in C.
    return ilist;

}

// Frees your bitmask. Safe to call dry. Returns 2 if
// it frees anything. 1 if it doesn't.
void free_bitmask(BITMASK *pBmask) {
    BMlist *pBMlist, *next;
    int found = 1;
    for(pBMlist = pBmask->int_list;pBMlist;pBMlist = next) {
        next = pBMlist->next;
        free_mem(pBMlist);
        found = 2;
    }
    return found;
}


// initialze a bitmask.
// bm = init_bitmask(NULL);
// init_bitmask(&bm);
// Both of above work.
BITMASK init_bitmask(BITMASK *bm) {
    static BITMASK bmzero;
    if (bm == 0)
        return bmzero;

    *bm = bmzero;
    return bmzero;
}

// #masks #bits #mask #vector #mask #vector ...
void load_bitmask(BITMASK *pBmask, FILE *fp) {
    int i;
    BMlist *pBMlist;

    pBmask->masks = fread_number(fp);
    pBmask->bits = fread_number(fp);

    for(i = 0;i < pBmask->masks;++i) {
        pBMlist = malloc(sizeof(BMlist));

        pBMlist->set = fread_number(fp);
        pBMlist->next = pBmask->int_list;
        pBmask->int_list = pBMlist;
        pBMlist->tar_mask = fread_number(fp);
    }
}

void save_bitmask(BITMASK *pBmask, FILE *fp) {
    BMlist *pBMlist;


    fprintf(fp, "%d %d", pBmask->masks, pBmask->bits);

    for(pBMlist = pBmask->int_list;pBMlist;pBMlist = pBMlist->next)
        fprintf(fp, " %d %ld", pBMlist->set, pBMlist->tar_mask);

    fprintf(fp, "\n");
}