Prototypes for merc.h
void read_unique_key(void);
void write_unique_key(void);
char *keygen(void);
int dupe_check(OBJ_DATA *obj);
void dupe_update(void);
char *grab_timestamp(void);
int check_player(CHAR_DATA *ch, CHAR_DATA *victim);
char *grab_date(time_t the_time);
char *grab_date_log(time_t the_time);
char *grab_time_log(time_t the_time);



char *grab_date(time_t the_time)
{
	static char lickmenow[200];
	struct tm *tm_ptr;

	lickmenow[0] = '\0';

	tm_ptr = gmtime(&the_time);

	//* Easier then my ex girlfriend. *//
	snprintf(lickmenow, 200, "%02d/%02d/%02d\n",tm_ptr->tm_year +1900, tm_ptr->tm_mon+1, tm_ptr->tm_mday);

	return lickmenow;	
}

// *Same as grab_date, just it uses - instead of /, and it doesn't put \n at the end* //
char *grab_date_log(time_t the_time)
{
	static char lickmenow[200];
	struct tm *tm_ptr;

	lickmenow[0] = '\0';

	tm_ptr = gmtime(&the_time);

	//* Easier then my ex girlfriend. *//
	snprintf(lickmenow, 200, "%02d-%02d-%02d",tm_ptr->tm_year +1900, tm_ptr->tm_mon+1, tm_ptr->tm_mday);

	return lickmenow;	
}


// *Return the time as a nice, little string.* //
char *grab_time(time_t the_time)
{
	static char lickmenow[200];
	struct tm *tm_ptr;

	lickmenow[0] = '\0';

	tm_ptr = gmtime(&the_time);

	//* Easier then my ex girlfriend. *//
	snprintf(lickmenow, 200, "%02d:%02d:%02d\n",tm_ptr->tm_hour, tm_ptr->tm_min, tm_ptr->tm_sec);

	return lickmenow;	
}

// *Same as grab_time, just without the \n at the end.* //
char *grab_time_log(time_t the_time)
{
	static char lickmenow[200];
	struct tm *tm_ptr;

	lickmenow[0] = '\0';

	tm_ptr = gmtime(&the_time);

	//* Easier then my ex girlfriend. *//
	snprintf(lickmenow, 200, "%02d:%02d:%02d",tm_ptr->tm_hour, tm_ptr->tm_min, tm_ptr->tm_sec);

	return lickmenow;	
}

char *keygen(void)
{
	static char a[10000];	// Yea, it can get this big
	char last_unique_key_buffer[20];	// never exceeds 20 unless you expand how high the key can get

	int x = 0, y = number_range(7, 30);	// up to 30 rotations of the loop, this could get big..

	// *Nullified eh?  Take that!* //
	a[0] = '\0';

	// *Another nullified piece of data* //
	last_unique_key_buffer[0] = '\0';
	//	snprintf(last_unique_key_buffer, 20, "l_key_%ld",last_unique_key); For thoes of us with out something called snprintf --Amras
	sprintf(last_unique_key_buffer, "l_key_%ld",last_unique_key);

	// *Over 1billion!?  reset please* //
	if(++last_unique_key > 2000000000 )	// Yes, thats 2billion.. woweee
	{
		//		log_string(LOG_SECURITY, "%s: last_unique_key reached 2bil, resetting to 0.", __PRETTY_FUNCTION__ ); --Amras
		bug("Last_unique_key reached 2bil, resetting to 0.", 0);
		last_unique_key = 0;
	}

	// *1 in 4 chance to save the unique_key, solong as the bootDb is false, only save after boots* //
	if(number_range(0, 3) == 0 && fBootDb == FALSE)
	{
		write_unique_key();
	}


	// Start off the unique-key, tis fun, Now contains special greetings to certain names in
	// the mudding community that have in some, way, shape or form helped or hindered me in
	// my growth as a coder, also just random crap, this is used to start off each unique
	// string, strcpy's, ie, sets the memory, so not strcating goes on prior to this.
	switch(number_range(0, 16))
	{
	case 0:	strcpy(a, "sstm_");				break; case 1:		strcpy(a, "unique_");		break;
	case 2:	strcpy(a, "key_");				break; case 3:		strcpy(a, "elvis_");		break;
	case 4:	strcpy(a, "lick_me_");			break; case 5:		strcpy(a, "sandstorm_");		break;
	case 6:	strcpy(a, "mages_");			break; case 7:		strcpy(a, "sanctuary_");		break;
	case 8:	strcpy(a, "mindeye_sux_");		break; case 9:		strcpy(a, "hello_runter_");	break;
	case 10:	strcpy(a, "morning_samson_");		break; case 11:	strcpy(a, "evening_davion_");	break;
	case 12:	strcpy(a, "afternoon_kyndig_");	break; case 13:	strcpy(a, "crap_");			break;
	case 14:	strcpy(a, "mudmagic_");			break; case 15:	strcpy(a, "dupe_this_");		break;
	case 16:	strcpy(a, "terminator_");		break;default:		strcpy(a, "unique_sstm_key_");break;
	}

	// *Yes, with crazy installed, you will get bigger loops.* //
	if(CRAZY_KEYGEN == 1)
		y = number_range(20, 45);	// 45... this is HUGE if you use this!

	// *Parse the generation list, expanded for new fun possabilities* //
	for(x = 0; x < y; ++x)
	{
		// *Start the switching* //
		switch(number_range(0, 27))
		{
		case 1: case 2: case 3: case 4:
			// Alphabet, lowercase
			switch(number_range(0, 24))
			{
			case 1: strcat(a, "a"); break;		case 2: strcat(a, "b"); break;
			case 3: strcat(a, "c"); break;		case 4: strcat(a, "d"); break;
			case 5: strcat(a, "e"); break;		case 6: strcat(a, "f"); break;
			case 7: strcat(a, "g"); break;		case 8: strcat(a, "h"); break;
			case 9: strcat(a, "i"); break;		case 10: strcat(a, "j"); break;
			case 11: strcat(a, "k"); break;		case 12: strcat(a, "l"); break;
			case 13: strcat(a, "m"); break;		case 14: strcat(a, "n"); break;
			case 15: strcat(a, "o"); break;		case 16: strcat(a, "p"); break;
			case 17: strcat(a, "q"); break;		case 18: strcat(a, "r"); break;
			case 19: strcat(a, "s"); break;		case 20: strcat(a, "t"); break;
			case 21: strcat(a, "u"); break;		case 22: strcat(a, "v"); break;
			case 23: strcat(a, "w"); break;		case 24: strcat(a, "x"); break;
			case 25: strcat(a, "y"); break;		default: strcat(a, "z"); break;
			}
			break;

		case 5: case 6: case 7:
			{ //Some compilers like brackets for new vars better --Amras
				char uick[3];

				// *Add a number to the list* //
				//snprintf(uick, 3, "%d", number_range(0, 9);
				sprintf(uick, "%d", number_range(0, 9)); //Do i even have to say why at this point? --Amras
				strcat(a, uick);
			}
			break;

		case 8: case 9: case 10: case 11: case 12:
			{ //Some compilers like brackets for new vars better --Amras
				char uick[3];

				// *Add a number to the list, larger numbers here.* //
				//snprintf(uick, 3, "%d", number_range(0, 99);
				sprintf(uick,"%d", number_range(0, 99)); //Do I even have to say why at this point? --Amras
				strcat(a, uick);
			}
			break;

		case 13: case 14: case 15: case 16: case 17: case 18:
			// *Afew ascii characters to make it more fun, no ~ cuz of string handling ;)*//
			switch(number_range(0, 17))
			{
			case 1: strcat(a, "!"); break;		case 2: strcat(a, "@"); break;
			case 3: strcat(a, "#"); break;		case 4: strcat(a, "$"); break;
			case 5: strcat(a, "^"); break;		case 6: strcat(a, "&"); break;
			case 7: strcat(a, "*"); break;		case 8: strcat(a, "("); break;
			case 9: strcat(a, ")"); break;		case 0: strcat(a, "|"); break;
			case 10: strcat(a, "["); break;		case 11: strcat(a, "]"); break;
			case 12: strcat(a, ";"); break;		case 13: strcat(a, "?"); break;
			case 14: strcat(a, "_"); break;		case 15: strcat(a, "+"); break;
			case 16: strcat(a, "="); break;		case 17: strcat(a, "`"); break;
			default: strcat(a, "-"); break;
			}
			break;

		case 19: case 20: case 21: case 22:
			// Alphabet, Upper Case
			switch(number_range(0, 24))
			{
			case 1: strcat(a, "A"); break;		case 2: strcat(a, "B"); break;
			case 3: strcat(a, "C"); break;		case 4: strcat(a, "D"); break;
			case 5: strcat(a, "E"); break;		case 6: strcat(a, "F"); break;
			case 7: strcat(a, "G"); break;		case 8: strcat(a, "H"); break;
			case 9: strcat(a, "I"); break;		case 10: strcat(a, "J"); break;
			case 11: strcat(a, "K"); break;		case 12: strcat(a, "L"); break;
			case 13: strcat(a, "M"); break;		case 14: strcat(a, "N"); break;
			case 15: strcat(a, "O"); break;		case 16: strcat(a, "P"); break;
			case 17: strcat(a, "Q"); break;		case 18: strcat(a, "R"); break;
			case 19: strcat(a, "S"); break;		case 20: strcat(a, "T"); break;
			case 21: strcat(a, "U"); break;		case 22: strcat(a, "V"); break;
			case 23: strcat(a, "W"); break;		case 24: strcat(a, "X"); break;
			case 25: strcat(a, "Y"); break;		default: strcat(a, "Z"); break;
			}
			break;

		case 23: case 24:
			switch(number_range(0, 3))
			{
			case 0: strcat(a, "_dave_"); break;	
			case 1: strcat(a, "_loves_"); break;
			case 2: strcat(a, "_courtney_"); break;	
			case 3: strcat(a, "_allot_"); break;

				// Default if something explodes.
			default: strcat(a, "_dave_loves_courtney_"); break;
			}
			break;

			// Case 25....  This is where each mud's unique keys will be really
			// Different based on skills/spells, races, and classes.
		case 25:
			{ //Brackets goood!!! --Amras
			int poo = 0;

			// Okay, LET THE FUN BEGIN!
			switch(number_range(0, 3))
			{
			case 1:
				poo = number_range(1, MAX_SKILL-1);

				// Null Name.??  Make it the number then'
				if(IS_NULLSTR(skill_table[poo].name))
				{
					char b[MAX_SKILL];
					b[0] = '\0';
					//snprintf(b, MAX_SKILL, "%d", poo); Yawn --Amras
					sprintf(b, "%d", poo);
					strcat(a, b);
				}
				else	// Not null... Grab the skill name
				{
					char b[3];
					b[0] = '\0';
					// Grab the first 3 letters of the skill name, interesting ;)
					//snprintf(b, 3, "%3s", skill_table[poo].name); Yawn --Amras
					sprintf(b, "%3s", skill_table[poo].name);
					strcat(a, b);
				}
				break;
			case 2:
				//I don't have a MAX_RACE SO!! Lets put a happy fun number --Amras
				//poo = number_range(1, MAX_RACE-1);
				poo = number_range(1, 10);
				if(IS_NULLSTR(race_table[poo].name))
				{
					//char b[MAX_RACE]; Can't figure this one out --Amras
					char b[MSL];
					b[0] ='\0';
					//snprintf(b, MAX_RACE], "%d", poo);  --Amras
					sprintf(b, "%d", poo);
					strcat(a, b);
				}
				else
				{
					char b[3];
					b[0] = '\0';
					//snprintf(b, 3, "%3s", race_table[poo].name); Holy screwy code batman!! --Amras
					sprintf(b, "%3s", race_table[poo].name);
					strcat(a, b);
				}
				break;
			case 3:
				poo = number_range(1, MAX_CLASS-1);
				if(IS_NULLSTR(class_table[poo].name))
				{
					char b[MAX_CLASS];
					b[0] ='\0';
					//snprintf(b, MAX_CLASS, "%d", poo); Why did the chicken cross the road? --Amras
					sprintf(b, "%d", poo);
					strcat(a, b);
				}
				else
				{
					char b[3];
					b[0] = '\0';
					//snprintf(b, 3, "%3s", class_table[poo].name); Because it didn't know what snprintf was for!!! --Amras
					sprintf(b, "%3s", class_table[poo].name);
					strcat(a, b);
				}
				break;
			default:	// Socials.. MUAHAHA
				//poo = number_range(1, MAX_SOCIAL-1); Nope! No MAX_SOCIAL Either --Amras
				poo = number_range(1, 20);
				if(IS_NULLSTR(social_table[poo].name))
				{
					//char b[MAX_SOCIAL]; I need some new random comments --Amras
					char b[MSL];
					b[0] ='\0';
					//snprintf(b, MAX_SOCIAL, "%d", poo); I swear I  will think of some --Amras
					sprintf(b, "%d", poo);
					strcat(a, b);
				}
				else
				{
					char b[3];
					b[0] = '\0';
					//snprintf(b, 3, "%3s", social_table[poo].name); My fingers hurt from all this fixing --Amras
					sprintf(b, "%3s", social_table[poo].name);
					strcat(a, b);
				}
				break;
			}
			}
			break;

		case 26:
			{ //This is getting a bit old --Amras
			int hud = number_range(0, 9);
			char huj[3];
			huj[0] = '\0';

			// Alphabet, Upper Case
			/* Figure it out yourself --Amras
			switch(number_range(0, 24))
			{
			case 1: snprintf(huj, 3, "A%d",hud); break;	case 2: snprintf(huj, 3, "B%d",hud); break;
			case 3: snprintf(huj, 3, "C%d",hud); break;	case 4: snprintf(huj, 3, "D%d",hud); break;
			case 5: snprintf(huj, 3, "E%d",hud); break;	case 6: snprintf(huj, 3, "F%d",hud); break;
			case 7: snprintf(huj, 3, "G%d",hud); break;	case 8: snprintf(huj, 3, "H%d",hud); break;
			case 9: snprintf(huj, 3, "I%d",hud); break;	case 10: snprintf(huj, 3,"J%d",hud); break;
			case 11: snprintf(huj, 3,"K%d",hud); break;	case 12: snprintf(huj, 3,"L%d",hud); break;
			case 13: snprintf(huj, 3,"M%d",hud); break;	case 14: snprintf(huj, 3,"N%d",hud); break;
			case 15: snprintf(huj, 3,"O%d",hud); break;	case 16: snprintf(huj, 3,"P%d",hud); break;
			case 17: snprintf(huj, 3,"Q%d",hud); break;	case 18: snprintf(huj, 3,"R%d",hud); break;
			case 19: snprintf(huj, 3,"S%d",hud); break;	case 20: snprintf(huj, 3,"T%d",hud); break;
			case 21: snprintf(huj, 3,"U%d",hud); break;	case 22: snprintf(huj, 3,"V%d",hud); break;
			case 23: snprintf(huj, 3,"W%d",hud); break;	case 24: snprintf(huj, 3,"X%d",hud); break;
			case 25: snprintf(huj, 3,"Y%d",hud); break;	default: snprintf(huj, 3,"Z%d",hud); break;
			}
			*/
			switch(number_range(0, 24))
			{
			case 1: sprintf(huj, "A%d",hud); break;	case 2: sprintf(huj, "B%d",hud); break;
			case 3: sprintf(huj, "C%d",hud); break;	case 4: sprintf(huj, "D%d",hud); break;
			case 5: sprintf(huj, "E%d",hud); break;	case 6: sprintf(huj, "F%d",hud); break;
			case 7: sprintf(huj, "G%d",hud); break;	case 8: sprintf(huj, "H%d",hud); break;
			case 9: sprintf(huj, "I%d",hud); break;	case 10: sprintf(huj,"J%d",hud); break;
			case 11: sprintf(huj, "K%d",hud); break;	case 12: sprintf(huj, "L%d",hud); break;
			case 13: sprintf(huj, "M%d",hud); break;	case 14: sprintf(huj, "N%d",hud); break;
			case 15: sprintf(huj, "O%d",hud); break;	case 16: sprintf(huj, "P%d",hud); break;
			case 17: sprintf(huj, "Q%d",hud); break;	case 18: sprintf(huj, "R%d",hud); break;
			case 19: sprintf(huj, "S%d",hud); break;	case 20: sprintf(huj, "T%d",hud); break;
			case 21: sprintf(huj, "U%d",hud); break;	case 22: sprintf(huj, "V%d",hud); break;
			case 23: sprintf(huj, "W%d",hud); break;	case 24: sprintf(huj, "X%d",hud); break;
			case 25: sprintf(huj, "Y%d",hud); break;	default: sprintf(huj, "Z%d",hud); break;
			}

			strcat(a, huj);
			}
			break;

		case 27:
			{ //This is getting a bit old --Amras
			int hud = number_range(0, 9);
			char huj[3];
			huj[0] = '\0';

			// Alphabet, LowerCase
			/*
			switch(number_range(0, 24))
			{
			case 1: snprintf(huj, 3, "a%d",hud); break;	case 2: snprintf(huj, 3, "b%d",hud); break;
			case 3: snprintf(huj, 3, "c%d",hud); break;	case 4: snprintf(huj, 3, "d%d",hud); break;
			case 5: snprintf(huj, 3, "e%d",hud); break;	case 6: snprintf(huj, 3, "f%d",hud); break;
			case 7: snprintf(huj, 3, "g%d",hud); break;	case 8: snprintf(huj, 3, "h%d",hud); break;
			case 9: snprintf(huj, 3, "i%d",hud); break;	case 10: snprintf(huj, 3,"j%d",hud); break;
			case 11: snprintf(huj, 3,"k%d",hud); break;	case 12: snprintf(huj, 3,"l%d",hud); break;
			case 13: snprintf(huj, 3,"m%d",hud); break;	case 14: snprintf(huj, 3,"n%d",hud); break;
			case 15: snprintf(huj, 3,"o%d",hud); break;	case 16: snprintf(huj, 3,"p%d",hud); break;
			case 17: snprintf(huj, 3,"q%d",hud); break;	case 18: snprintf(huj, 3,"r%d",hud); break;
			case 19: snprintf(huj, 3,"s%d",hud); break;	case 20: snprintf(huj, 3,"t%d",hud); break;
			case 21: snprintf(huj, 3,"u%d",hud); break;	case 22: snprintf(huj, 3,"v%d",hud); break;
			case 23: snprintf(huj, 3,"w%d",hud); break;	case 24: snprintf(huj, 3,"x%d",hud); break;
			case 25: snprintf(huj, 3,"y%d",hud); break;	default: snprintf(huj, 3,"z%d",hud); break;
			} --Amras
			*/
			switch(number_range(0, 24))
			{
			case 1: sprintf(huj, "a%d",hud); break;	case 2: sprintf(huj, "b%d",hud); break;
			case 3: sprintf(huj, "c%d",hud); break;	case 4: sprintf(huj, "d%d",hud); break;
			case 5: sprintf(huj, "e%d",hud); break;	case 6: sprintf(huj, "f%d",hud); break;
			case 7: sprintf(huj, "g%d",hud); break;	case 8: sprintf(huj, "h%d",hud); break;
			case 9: sprintf(huj, "i%d",hud); break;	case 10: sprintf(huj,"j%d",hud); break;
			case 11: sprintf(huj, "k%d",hud); break;	case 12: sprintf(huj, "l%d",hud); break;
			case 13: sprintf(huj, "m%d",hud); break;	case 14: sprintf(huj, "n%d",hud); break;
			case 15: sprintf(huj, "o%d",hud); break;	case 16: sprintf(huj, "p%d",hud); break;
			case 17: sprintf(huj, "q%d",hud); break;	case 18: sprintf(huj, "r%d",hud); break;
			case 19: sprintf(huj, "s%d",hud); break;	case 20: sprintf(huj, "t%d",hud); break;
			case 21: sprintf(huj, "u%d",hud); break;	case 22: sprintf(huj, "v%d",hud); break;
			case 23: sprintf(huj, "w%d",hud); break;	case 24: sprintf(huj, "x%d",hud); break;
			case 25: sprintf(huj, "y%d",hud); break;	default: sprintf(huj, "z%d",hud); break;
			}

			strcat(a, huj);
			}
			break;

		}
	}

	// Let the crazies begin, this will REALLY expand a generated key greatly!
	if(CRAZY_KEYGEN == 1)
	{
		// *This part of the keygen is really retarded, there is no point* //
		// *in doing this, but at the same time, it makes keygens more   * //
		// *random, which is fine, considering it gets MD5'd now         * //
		//I don't have the internal grab_timestamp SO I removed it --Amras
		if(number_range(0,1) == 1)		strcat(a, grab_timestamp());
		if(number_range(0,1) == 1)		strcat(a, "aeiou-sometimes-y");
		if(number_range(0,1) == 1)		strcat(a, "another-brick-in-the-wall");
		if(number_range(0,1) == 1)		strcat(a, "time...time...");
		if(number_range(0,1) == 1)		strcat(a, "elvis_loves_you");
		if(number_range(0,1) == 1)		strcat(a, "thankyou...thankyou.very.much.");
		if(number_range(0,1) == 1)		strcat(a, "windows-xp");
		if(number_range(0,1) == 1)		strcat(a, grab_timestamp());
	}


	// *Cannot forget the last_unique_key_buffer, tis abit required!* //
	strcat(a, last_unique_key_buffer);

	// Nullify the end of the data, essentaily stop leaks.
	a[strlen(a)] = '\0';


	// *********************************************************************** //
	// * MD5 the string if it is longer then 15 characters(which it should be* //
	// * md5 is now a localy powered system, unlike the samson md5, this     * //
	// * doesn't have a max size for the md5 to use :)                       * //
	// * If the string is less then 15, it won't md5, but the chances of that* //
	// * happening are far, and few between.  so enjoy                       * //
	// *********************************************************************** //
	if(strlen(a) > 15) 
		//a = handle_md5(a); Ummmm ok then? --Amras
		strcat(a, handle_md5(a));


	// Strdup's the value, requires disposal, (ie, free_string(blah) )
	//If this is already a static char then we do not have to dup it! --Amras
	//return str_dup(a);
	return a;
}

// *time-stamp!* //
char *grab_timestamp(void)
{
	if(number_range(0, 1) == 1)
		return grab_time_log(current_time);

	return grab_date_log(current_time);
}


// Check the main OBJ against all the objects in the obj_list
int dupe_check(OBJ_DATA *obj)
{
	//obj_data *list, *list_next; --Amras
	OBJ_DATA *list, *list_next;
	int count = 0;
	bool remove_object = FALSE;
	/*
	* I am not to sure what log system was used here, but its not mine soo... for more compatability, 
	* here is a log system that works with stock ROM (the ole' sprintf() and log_string() ;)) --Amras
	*/
	char buf[MSL]; 

	// *Object list manipulation begins... Now* //
//	for(list = obj_list; list; list = list_next) Have to find the right object list before it can be manipulated --Amras
	for(list = object_list; list; list = list->next)
	{
		list_next = list->next;

		// Skip this one cuz frankly, it will be 100% match :P silly people..
		if(list == obj)
			continue;

		// not the same vnum, then its not a duplicate!
		//if(list->vnum != obj->vnum) Nice try... --Amras
		if(list->pIndexData->vnum != obj->pIndexData->vnum)
			continue;

		// *check the timestamp* //
		if(list->timestamp == obj->timestamp)
		{
			// We roped us a duplicate, CASE SENSETIVE!
			if(strcasecmp(list->unique_key, obj->unique_key))
			{
				// Lets log it, and extract the duplicate!
				// Uses my released log system, comment out if you don't have my system
				if(obj->in_room)
				{
					//	log_string(LOG_SECURITY, "Duplicate found!  %s->%s, removing duplicate!", obj->in_room->name, obj->short_descr);
					sprintf(buf, "Duplicate found!  %s->%s, removing duplicate!", obj->in_room->name, obj->short_descr);
					log_string(buf); //Amras 
				}
				else if(obj->carried_by)
				{
					if(IS_IMMORTAL(obj->carried_by))
					{
						//log_string(LOG_SECURITY, "Duplicate found!  %s->%s, removing duplicate!(Immortal with duped items! Check logs!)", obj->carried_by->name, obj->short_descr);
						sprintf(buf, "Duplicate found!  %s->%s, removing duplicate!(Immortal with duped items! Check logs!)", obj->carried_by->name, obj->short_descr);
						log_string(buf); //Amras 
					}
					else
					{
						//log_string(LOG_SECURITY, "Duplicate found!  %s->%s, removing duplicate!", obj->carried_by->name, obj->short_descr);
						sprintf(buf, "Duplicate found!  %s->%s, removing duplicate!", obj->carried_by->name, obj->short_descr);
						log_string(buf); //Amras 
					}
				}
				else
				{
					//log_string(LOG_SECURITY, "Duplicate found!  %s, removing duplicate!",  obj->short_descr);
					sprintf(buf, "Duplicate found!  %s, removing duplicate!",  obj->short_descr);
					log_string(buf); //Amras 
				}

				// Strip the object from wherever it is.
				extract_obj(list);
				// *Evil cheating bastards... dupe me once, shame on me, dupe me twice.. Fuck you!* //
				/* As tedious as it is, C does not know what true and false are --Amras
				if(obj->has_duped = true)
					remove_object = true;
				obj->has_duped = true;
				*/
				if(obj->has_duped == TRUE)
					remove_object = TRUE;
				obj->has_duped = TRUE;
				++count;
				continue;
			}
		}

		// *Same check again, just go through its contains list.* //
		if(list->contains)
		{
			//obj_data *cont_list, *cont_next; Wrong again!!! --Amras
			OBJ_DATA *cont_list, *cont_next;

			// *Search for duplicates within containers* //
			for(cont_list = list->contains; cont_list; cont_list = cont_next)
			{
				cont_next = cont_list->next_content;

				// *check the timestamp* //
				if(cont_list->timestamp == obj->timestamp)
				{
					// We roped us a duplicate, CASE SENSETIVE!
					if(strcasecmp(cont_list->unique_key, obj->unique_key))
					{
						// Lets log it, and extract the duplicate!
						// Uses my released log system, comment out if you don't have my system
						if(list->carried_by)	// Just checking
						{
							if(IS_IMMORTAL(list->carried_by))
							{
								//log_string(LOG_SECURITY, "Duplicate found!  %s->%s, removing duplicate!(Duped item in object found on immortal: %s)", list->short_descr, cont_list->short_descr, list->carried_by->name);
								sprintf(buf ,"Duplicate found!  %s->%s, removing duplicate!(Duped item in object found on immortal: %s)", list->short_descr, cont_list->short_descr, list->carried_by->name);
								log_string(buf); //Amras 
							}
							else
							{
								//log_string(LOG_SECURITY, "Duplicate found!  %s->%s, removing duplicate!", list->short_descr, cont_list->short_descr);
								sprintf(buf, "Duplicate found!  %s->%s, removing duplicate!", list->short_descr, cont_list->short_descr);
								log_string(buf); //Amras 
							}
						}
						else
						{
							//log_string(LOG_SECURITY, "Duplicate found!  %s->%s, removing duplicate!", list->short_descr, cont_list->short_descr);
							sprintf(buf, "Duplicate found!  %s->%s, removing duplicate!", list->short_descr, cont_list->short_descr);
							log_string(buf); //Amras 
						}

						// Strip the object from wherever it is.
						extract_obj(cont_list);
						// *Evil cheating bastards... dupe me once, shame on me, dupe me twice.. Fuck you!* //
						/* *just crys* --Amras
						if(obj->has_duped = true)
							remove_object = true;
						obj->has_duped = true;
						*/
						if(obj->has_duped == TRUE)
							remove_object = TRUE;
						obj->has_duped = TRUE;
						++count;
						continue;
					}
				}

			}
		}

	}

	// *Take that you evil cheating bastards!* //
	if(remove_object)
		extract_obj(obj);

	// Exit function... sad that i commented this..
	return count;
}


// *Oh yeah!  List checking fun!* //
// *Only use this if you are using option 1* //
// *Updated* //
void dupe_update(void)
{
	//obj_data *list, *next_list; --Amras
	OBJ_DATA *list, *next_list;
	char buf[MSL];
	int count = 0;

	// *Because this can be a long process, we will only do it at random.* //
	if(number_range(0, 100) == 0)	// Small chance, but when it happens, its good cleaning :)
	{
		// Uses my time-of-day system and my log system, remove if you don't use.
		//log_string(LOG_SECURITY, "Duplication Check started at:  %s", grab_time_log(current_time)); --Amras
		sprintf(buf, "Duplication Check started at:  %s", grab_time_log(current_time));
		log_string(buf);

		// *Parse through the list for duplicates, just-incase...* //
		//for(list = obj_list; list; list = next_list) Getting Old --Amras
		for(list = object_list; list; list = next_list)
		{
			int x = 0;
			next_list = list->next;
			x = dupe_check(list);	// Compare to the rest of the lists

			// Ick, fixed this, much better now.
			count =+ x;
		}

		// *Take that Boyo!* //
		if(count > 0)
		{
			//log_string(LOG_SECURITY, "Dupe_check cleared %d duplicate items!", count);
			sprintf(buf, "Dupe_check cleared %d duplicate items!", count);
			log_string(buf); //Amras
		}
	}
	else	// *Yes, we now parse the player-list, less checks then the above object_list.. we hope..* //
	{
		CHAR_DATA *ick, *next_ick;

		// *Parse through the list of characters next* //
		for(ick = char_list; ick; ick = next_ick)
		{
			next_ick = ick->next;
			// *Ooooooooooh!* //
			count =+ check_player(NULL, ick);

		}

		if(count > 0)
		{
			//log_string(LOG_SECURITY, "Dupe_check cleared %d duplicate items!", count);
			sprintf(buf, "Dupe_check cleared %d duplicate items!", count);
			log_string(buf); //Amras
		}

	}
	return;
}

// Uh oh!?  Indevidual player-checking!
int check_player(CHAR_DATA *ch, CHAR_DATA *victim)
{
	//obj_data *list, *next_list; --Amras
	OBJ_DATA *list, *next_list;
	char buf[MSL];
	int count = 0;

	for (list = victim->carrying; list; list = next_list)
	{
		next_list = list->next;

		count =+ dupe_check(list);
	}

	if(ch)
		printf_to_char(ch, "%s had %d dupes.", count);

	// *Take this... Asshole!* //
	if(count > 0)
	{
		//log_string(LOG_SECURITY, "Dupe_check cleared %d duplicate items from %s", count, victim->name);
		sprintf(buf, "Dupe_check cleared %d duplicate items from %s", count, victim->name);
		log_string(buf); //Amras
	}

	return count;

}

// Force a dupecheck to start, updated for confirmation.
// Uses printf_to_char snippet by erwin, download if you don't have something similar.
void do_dupecheck(CHAR_DATA *ch, char *argument)
{
	char arg[MAX_INPUT_LENGTH];
	char buf[MSL];
	int count = 0;
	//obj_data *list, *next_list; --Amras
	OBJ_DATA *list, *next_list;
#define DUPE_KEYWORD "confirm"	// Bad Security attempt here!

	argument = one_argument(argument, arg);

	if(IS_NULLSTR(argument))
	{
		printf_to_char(ch, "You must confirm the dupecheck.  Ie  dupecheck <victim/all> %s\n\r", DUPE_KEYWORD);
		return;
	}

	if(!is_exact_name(argument, DUPE_KEYWORD))
	{
		send_to_char("Please confirm with the proper keyword!\n\r",ch);
		return;
	}


	if(is_exact_name(arg, "all"))
	{
		CHAR_DATA *ick, *next_ick;

		// Uses my time-of-day system and my log system, remove if you don't use.
		//log_string(LOG_SECURITY, "Duplication Check started at:  %s", grab_time_log(current_time));
		sprintf(buf, "Duplication Check started at:  %s", grab_time_log(current_time));
		log_string(buf);

		// *Parse through the list for duplicates, just-incase...* //
		//for(list = obj_list; list; list = next_list) --Amras
		for(list = object_list; list; list = next_list)
		{
			int x = 0;
			next_list = list->next;
			x = dupe_check(list);
			count = count + x;
		}

		// *Parse through the list of characters next* //
		for(ick = char_list; ick; ick = next_ick)
		{
			next_ick = ick->next;
			// *Ooooooooooh!* //
			count =+ check_player(NULL, ick);

		}

		// *Take that Boyo!* //
		if(count > 0)
		{
			//log_string(LOG_SECURITY, "Dupe_check cleared %d duplicate items!", count);
			sprintf(buf, "Dupe_check cleared %d duplicate items!", count);
			log_string(buf); //Amras
		}
	}
	else
	{
		CHAR_DATA *victim;
		if((victim = get_char_world(ch, arg)) == NULL)
		{
			send_to_char("They are not here!\n\r",ch);
			return;
		}

		// Booya!
		check_player(ch, victim);
		return;
	}
	return;
}


void write_unique_key(void)
{
	FILE *fp;

	if((fp = fopen(UNIQUE_KEY_FILE, "w")) == NULL)
	{
		//log_string(LOG_BUG, "Uh oh! couldn't write " UNIQUE_KEY_FILE "for writing");
		log_string("Uh oh! couldn't write " UNIQUE_KEY_FILE "for writing"); //Amras
		return;
	}

	// Simple as pie
	fprintf(fp, "%ld\n",last_unique_key);
	fclose(fp);
	return;
}

void read_unique_key(void)
{
	FILE * fp;

	if((fp = fopen(UNIQUE_KEY_FILE, "r")) == NULL)
	{
		//log_string(LOG_BUG, "Uh oh! couldn't write " UNIQUE_KEY_FILE "for reading");
		log_string("Uh oh! couldn't write " UNIQUE_KEY_FILE "for reading"); //Amras
		return;
	}

	// Simple as pie!
	last_unique_key = fread_number(fp);
	fclose(fp);
	return;

}