#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <string.h>
#define BUCKETS 100
struct s_stringMap;
typedef struct s_stringMap {
const char *key;
const char *value;
struct s_stringMap *next;
} stringMap;
unsigned int hashmap( const char *s );
void hash_init( stringMap *map );
void hash_add( stringMap *map, const char *k, const char *v );
const char * hash_find(stringMap *map, const char *k);
unsigned int hashmap( const char *s )
{
unsigned int hash = 0;
if(!s || !*s) return 0;
do {
hash += *s;
hash *= 13;
s++;
} while (*s);
return hash % BUCKETS;
}
void hash_init( stringMap *map )
{
int i;
for(i = 0; i < BUCKETS; i++)
{
map[i].key = NULL;
map[i].value = NULL;
map[i].next = NULL;
}
}
void hash_add( stringMap *map, const char *k, const char *v )
{
unsigned int hashcode;
stringMap *p;
hashcode = hashmap(k);
p = &map[hashcode];
while(p->key && strcmp(p->key, k) && p->next)
p = p->next;
if(!p->key) {
/* First node? */
p->key = (const char *)strdup(k);
p->value = (const char *)strdup(v);
p->next = NULL;
} else if(!strcmp(p->key, k)) {
/* Found our match! */
if(p->value)
free((void *)p->value);
p->value = (const char *)strdup(v);
} else {
/* New key */
p->next = (stringMap *)calloc(1, sizeof(stringMap));
p = p->next;
p->key = (const char *)strdup(k);
p->value = (const char *)strdup(v);
p->next = NULL;
}
}
const char * hash_find(stringMap *map, const char *k)
{
unsigned int hashcode;
stringMap *p;
hashcode = hashmap(k);
p = &map[hashcode];
while(p->key && strcmp(p->key, k) && p->next)
p = p->next;
if(!p->key)
return NULL;
if(!strcmp(p->key, k))
return p->value;
return NULL;
}
#define IS_WEAPON_STAT(obj,stat)(IS_SET((obj)->value[4],(stat)))
enum {
ENUM_QUIET,
};
fprintf(fp, "Flags %s End\n", flag_bit_name(ch->flags));
case 'Q':
if (!str_cmp(flag, "quiet"))
BITSET(ch->flags, ENUM_QUIET);
#ifndef _Flag_hpp
#define _Flag_hpp
// **************************************************************
// our flag system, this is used in all sorts of places; and is
// essentialy a god when it comes to bitsetting; (well not really)
// but it is simplistic, which is important.
// this class is virtualized for a reason, we want to inherit this
// class and have direct access to the flag manipulation.
class Flag
{
public:
Flag()
{
highestFlag = 0;
}
virtual ~Flag() { }
private:
std::map<int, bool>mFlag;
int highestFlag;
public:
void cleanFlags ( void )
{
std::map<int, bool>::iterator iter, iter_next;
for ( iter = mFlag.begin(); iter != mFlag.end(); iter = iter_next )
{
int x = iter->first;
bool s = iter->second;
iter_next = ++iter;
// strip out our old flag.
if ( !s )
{
mFlag.erase ( x );
}
}
}
bool hasFlag ( int flag )
{
std::map<int, bool>::iterator iter, iter_next;
for ( iter = mFlag.begin(); iter != mFlag.end(); iter = iter_next )
{
int x = iter->first;
bool s = iter->second;
iter_next = ++iter;
// could be true or false?
if ( x == flag )
{
return s;
}
}
return false;
}
// toggle the flag on/off!
void toggleFlag ( int flag )
{
std::map<int, bool>::iterator iter, iter_next;
// set the flag
if ( !hasFlag ( flag ) )
{
mFlag[flag] = true;
if ( flag > highestFlag )
{
highestFlag = flag;
}
return;
}
// get rid of the flag
for ( iter = mFlag.begin(); iter != mFlag.end(); iter = iter_next )
{
int x = iter->first;
iter_next = ++iter;
if ( x == flag )
{
mFlag.erase ( x );
break;
}
}
}
void setFlag ( int flag, bool value )
{
// removing the flag!
if ( hasFlag ( flag ) && !value )
{
std::map<int, bool>::iterator iter, iter_next;
for ( iter = mFlag.begin(); iter != mFlag.end(); iter = iter_next )
{
int x = iter->first;
iter_next = ++iter;
if ( x == flag )
{
mFlag.erase ( x );
break;
}
}
return;
}
// we don't have it, so we don't set it (save memory)
if ( !value )
{
return;
}
mFlag[flag] = value;
if ( flag > highestFlag )
{
highestFlag = flag;
}
return;
}
std::string flagToString ( void )
{
std::string retStr ( "" );
int x = 0;
while ( x <= highestFlag )
{
char buf[10];
// – February 15 2014
// – in a std::map, when you call mFlag[x]
// – if the iterator to the location of x doesn't exist
// – it creates it with a default value, we later clean this
// – up and remove that pointer to the empty data.
// – savings are minimal, but worth it.
// – David Simmerson (Omega)
snprintf ( buf, 10, "%d", mFlag[x] );
retStr.append ( buf );
// increment towards our final destination
x++;
}
// this cleans up our 'other' flags. ones that are 0 instead of 1
// with std::map's when you access them, it creates the default value
// so using mFlag[x], if it wasn't set before, it sets it. cleanFlags
// strips all those that are set to 0; minimal memory saved, but long-term
// it could be a healthy life saver.
// – possible testing to verify if this works the way intended or if is a pointless attempt
// – to conserve minimal memory. More testing required.
// –cleanFlags();
return retStr;
}
void stringToFlag ( const std::string &str )
{
size_t x = 0;
while ( str[x] != '\0' )
{
if ( x > str.length() )
{
break;
}
// only if we are set to 1 shall we add it :)
if ( str[x] == '1' )
{
mFlag[x] = true;
highestFlag = x;
}
// increment!
x++;
}
return;
}
};
#endif
typedef enum
{
CF_SEE_LOGS = 0,
CF_SEE_BUGS,
CF_SEE_SECURITY,
CF_SEE_LOGINS,
CF_SEE_CTIMER,
CF_SEE_ABORT,
CF_SEE_SCRIPT,
CF_SEE_COMMANDS,
CF_SEE_DEBUG,
CF_SEE_LUA,
CF_SEE_MISSIONS_COMPLETE,
CF_SEE_OLC,
CF_SEE_USAGE,
CF_SEE_UNUSED5,
CF_SEE_UNUSED6
} game_flags;
WRITE_COMMENT(fp, "FLAGS : SET BY ONES AND ZEROS TO REPRESENT ON/OFF");
WRITE_STRING( fp, INDENT"FLAGS", C_STR ( flagToString() ) );
case 'F':
if ( SameString ( word, "Flags" ) )
{
fMatch = true;
const char *tmpStr = readString ( fp );
stringToFlag ( tmpStr );
delete [] tmpStr;
}
break;
if ( cr->hasFlag ( CR_SEE_LOGS ) )
cr->setFlag( CR_SEE_LOGS, true); // false removes the flag, true sets the flag.
enum {
ENUM_QUIET,
};
fprintf(fp, "Flags %s End\n", flag_bit_name(ch->flags));
case 'Q':
if (!str_cmp(flag, "quiet"))
BITSET(ch->flags, ENUM_QUIET);
with that
char* pcdata->visitedroom = (char *)calloc(MAX_MAP_ROOM_SAVED , sizeof(char));
bool is_room_visited(CHAR_DATA *ch, ROOM_INDEX_DATA *pRoomIndex) {
if ( !ch || !ch->pcdata || !pRoomIndex)
return FALSE;
if (is_demi(ch))
return TRUE;
return ch->pcdata->visitedroom[pRoomIndex->vnum / 8] & (1 << (pRoomIndex->vnum % 8)) ? TRUE : FALSE;
}
bool is_room_sn_visited(CHAR_DATA *ch, unsigned int vnum) {
if ( !ch || !ch->pcdata)
return FALSE;
if (is_demi(ch))
return TRUE;
return ch->pcdata->visitedroom[vnum / 8] & (1 << (vnum % 8)) ? TRUE : FALSE;
}
void set_room_sn_visited(CHAR_DATA *ch, unsigned int vnum) {
if (!is_room_sn_visited(ch, vnum)) {
//TODO send room info with msdp
}
ch->pcdata->visitedroom[vnum / 8] |= (1 << (vnum % 8));
}
void set_room_visited(CHAR_DATA *ch, ROOM_INDEX_DATA *pRoomIndex) {
if ( !ch || !ch->pcdata || !pRoomIndex || IS_SET(pRoomIndex->room_flags, ROOM_NO_MAP))
return;
set_room_sn_visited(ch, pRoomIndex->vnum);
}
void unset_room_sn_visited(CHAR_DATA *ch, unsigned int vnum) {
ch->pcdata->visitedroom[vnum / 8] &= ~(1 << (vnum % 8));
}
#define BITMASK(b) (1 << ((b) % CHAR_BIT))
#define BITSLOT(b) ((b) / CHAR_BIT)
#define BITSET(a, b) ((a)[BITSLOT(b)] |= BITMASK(b))
#define BITCLEAR(a, b) ((a)[BITSLOT(b)] &= ~BITMASK(b))
#define BITTEST(a, b) ((a)[BITSLOT(b)] & BITMASK(b))
#define BITNSLOTS(nb) ((nb + CHAR_BIT - 1) / CHAR_BIT)
char *flag_bit_name(char *flags) {
static char buf[MSL];
buf[0] = '\0';
if (BITTEST(flags, FLAG_QUIET))
strncat(buf, " quiet", sizeof(buf) - strlen(buf) - 1);
//other if checks for any other bits you have…
return (buf[0] != '\0') ? buf + 1 : "none";
}
I assume I could expand to 64 bits relatively easily, but I'd rather implement something more flexible.
My goals are a solution that:
- provides an infinite number of bits/flags (or more than I'd ever need)
- makes it relatively easy to read/write the bits as a list of string "flags" (i.e., no more parsing "ABDgaa" or raw integer values)
- is hopefully a least path of resistance in implementing into my existing MUD (OLC, pfile saving/loading, etc.)
- is flexible enough to allow adding/removing of bits/flags over time
I don't care about being able to use straight bitwise operations (e.g., FOO|BAR).
I'm not overly concerning about memory usage, within reason.
The MUD doesn't use any C++ features right now, but compiles cleanly in g++.
Things I've looked at:
- wrapping std::bitset, not sure how
- Runter's bit system, would require changing the loading/saving code, but otherwise looks nice
- using plain old arrays of ints and functions/macros to manipulate the ints