/* Explored Room Code
 * This snippet is intended for just plain old ROM, though it'll probably work on just about any codebase
 * that uses a unique number to identify the room.
 * Written By Davion Kalhen of MudBytes.net one boring Saturday morning!
 */

/***
 **In act_move.c at the top with the other #include's add
 */
#include <malloc.h>

/***
 **In act_move.c just toss these functions in at the bottom.
 */

//Check to see if a vnum has been explored
bool explored_vnum(CHAR_DATA *ch, int vnum)
{	int mask = vnum / 32; //Get which bucket the bit is in
	unsigned int bit = vnum % 32; //Get which bit in the bucket we're playing with
	EXPLORE_HOLDER *pExp; //The buckets bucket.

	if(bit == 0 ) // % 32 will return 0 if vnum == 32, instead make it the last bit of the previous mask
	{	mask--;
		bit = 32;
	}

	for(pExp = ch->pcdata->explored->bits ; pExp ; pExp = pExp->next ) //Iterate through the buckets
	{	if(pExp->mask != mask)
			continue;
		//Found the right bucket, might be explored.
		if(IS_SET(pExp->bits, ( 1 << bit ) ) ) //Convert bit to 2^(bit-1) and see if it's set.
			return TRUE;
		return FALSE; //Return immediately. This value wont be in any other bucket.
	}
	return FALSE;
}
//Explore a vnum. Assume it's not explored and just set it.
void explore_vnum(CHAR_DATA *ch, int vnum )
{	int mask = vnum / 32; //Get which bucket it will be in
	unsigned int bit = vnum % 32; // Get which bit to set
	EXPLORE_HOLDER *pExp; //The buckets bucket.

	if(bit == 0 ) // % 32 will return 0 if vnum is a multiple 32, instead make it the last bit of the previous mask
	{	mask--;
		bit = 32;
	}

	//Find the bucket.
	for(pExp = ch->pcdata->explored->bits ; pExp ; pExp = pExp->next )
		if(pExp->mask == mask)
			break;

	if(!pExp) //If it's null, bucket not found, we'll whip one up.
	{	pExp = (EXPLORE_HOLDER *)calloc(sizeof(*pExp), 1); //Alloc and zero
		pExp->mask = mask;
		pExp->next = ch->pcdata->explored->bits; //Add to
		ch->pcdata->explored->bits = pExp;       //the list
	}

	SET_BIT(pExp->bits, ( 1 << bit ) ); //Convert bit to 2^(bit-1) and set
	ch->pcdata->explored->set++; //Tell how many rooms we've explored
}
	

//Explore a vnum.
void check_explore( CHAR_DATA *ch, ROOM_INDEX_DATA *pRoom )
{	if(IS_NPC(ch) ) return;

	
	if(explored_vnum(ch, pRoom->vnum) )
		return;

	explore_vnum(ch, pRoom->vnum);
}

void do_explored(CHAR_DATA *ch, char *argument )
{	char buf[MAX_STRING_LENGTH];
	sprintf(buf, "You have explored %d room%s!{x\r\n", ch->pcdata->explored->set, (ch->pcdata->explored->set == 1 ? "" : "s") );
	send_to_char(buf,ch);

//This shows all the rooms they've explored. Probably don't need mortals seeing this, and for immortals... it'd get really spammy. Mostly an example.
/*	for(pExp = ch->pcdata->explored->bits ; pExp ; pExp = pExp->next )
	{	for(bit = 1 ; bit <= 32 ; ++bit )
		{	if(IS_SET(pExp->bits, (1 << bit) ) )
			{	sprintf(buf, "[%-5d]", (pExp->mask * 32 + bit) );
				send_to_char(buf,ch);
			}
		}
		send_to_char("\r\n",ch);
	}
*/
	return;
}

/***
 **Now open up merc.h and add this above the struct pcdata definition.
 */

//Exploration holder.
//Basically just a linked list of int's where we only use the bits.
typedef struct explore_holder
{	struct explore_holder *next;
	unsigned int bits;
	int mask;
} EXPLORE_HOLDER;

typedef struct exploration_data
{	EXPLORE_HOLDER *bits;
	int set;
} EXPLORE_DATA;

/***
 **Add this to the bottom of the pcdata struct.
 */
	EXPLORE_DATA *explored;

/***
 **Lower down in merc.h look for the prototypes and add these under act_move.c
 */
void check_explore args( ( CHAR_DATA *, ROOM_INDEX_DATA * ) );
void explore_vnum args( (CHAR_DATA *, int ) );
bool explored_vnum args( (CHAR_DATA *, int ) );


/***
 **In recycle.c locate new_pcdata and add this right above the call to VALIDATE(pcdata);
 */

pcdata->explored = (EXPLORE_DATA *)calloc(1, sizeof(*(pcdata->explored) ) ); //Allocate explored data

/***
 **Right below in free_pcdata() add this before INVALIDATE(pcdata);
 */
	{	EXPLORE_HOLDER *pExp, *e_next;
		for(pExp = pcdata->explored->bits ; pExp ; pExp = e_next )
		{	e_next = pExp->next;
			free(pExp);
		}
	}


/***
 **Open up handler.c and find char_to_room. Add this right after a player is added to the list (pRoomIndex->people = ch;)
 */

    check_explore(ch, pRoomIndex); //Explore the room


/***
 **Open up save.c and under fwrite_char, and before it writes alias' add
 */
	if(ch->pcdata->explored->set > 0 )
	{	EXPLORE_HOLDER *pExp;

		fprintf(fp, "Explored %d\n", ch->pcdata->explored->set);
		for(pExp = ch->pcdata->explored->bits ; pExp ; pExp = pExp->next )
			fprintf(fp, "%d %d\n", pExp->mask, pExp->bits );
		fprintf(fp, "-1 -1\n" );
	}


/***
 **Look down farther for fread_char under case 'E' add this
 */
		if(!str_cmp(word, "Explored") )
		{	int mask, bit;
			EXPLORE_HOLDER *pExp;
			ch->pcdata->explored->set = fread_number(fp);
			while(1)
			{	mask = fread_number(fp);
				bit = fread_number(fp);
				if(mask == -1)
					break;
				for(pExp = ch->pcdata->explored->bits ; pExp ; pExp = pExp->next )
					if(pExp->mask == mask)
						break;
				if(!pExp)
				{	pExp = (EXPLORE_HOLDER *)calloc(1, sizeof(*pExp) );
					pExp->next = ch->pcdata->explored->bits;
					ch->pcdata->explored->bits = pExp;
					pExp->mask = mask;
				}
				pExp->bits = bit;
			}
			fMatch = TRUE;
		}

/***
 **Open up interp.c and throw this in the command table (I put mine near kill, cuz the functions are similar!)
 */
{ "explored",	do_explored,		POS_RESTING,	 0,  LOG_NORMAL, 1 },

/***
 **Add this in interp.h wherever
 */

DECLARE_DO_FUN( do_explored		);


/***
 **All you have to do now is do a clean make, and copyover! Everything should start working automatically!
 */