lurf/area/
lurf/build/testing/
lurf/log/
lurf/player/
lurf/player/backup/
/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *                                                                         *
 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
 *  Chastain, Michael Quan, and Mitchell Tse.                              *
 *                                                                         *
 *  In order to use any part of this Merc Diku Mud, you must comply with   *
 *  both the original Diku license in 'license.doc' as well the Merc       *
 *  license in 'license.txt'.  In particular, you may not remove either of *
 *  these copyright notices.                                               *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  *
 ***************************************************************************/
#include <glib.h>

#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <merc.h>
#include <recycle.h>
#include <olc.h>
#include <interp.h>
#include <fight.h>
#include <tables.h>
#include <power.h>

extern bool check_safe_imm args((CHAR_DATA *ch));

CHAR_DATA *get_char_area( CHAR_DATA *ch,char *argument)
{
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *ach;
	int number,count;
	
	if ( (ach = get_char_room( ch, argument )) != NULL )
		return ach;
	
	number = number_argument( argument, arg );
	count = 0;
	for ( ach = char_list; ach != NULL; ach = ach->next )
	{
		if (ach->in_room->area != ch->in_room->area
			||  !can_see( ch, ach ) || !is_name( arg, ach->name->str ))
			continue;
		if (++count == number)
			return ach;
	}
	
	return ach;
}

CHAR_DATA *get_char_id( long id )
{
	CHAR_DATA *wch;
	
	for ( wch = char_list; wch != NULL ; wch = wch->next )
	{
		if ( wch->id == id ) return wch;
	}
	
	return NULL;
}

/*
 * Move a char out of a room.
 */
void char_from_room( CHAR_DATA *ch )
{
	OBJ_DATA *obj;
	
	if ( ch->in_room == NULL )
	{
		
		bug( "Char_from_room: NULL.", 0 );
		return;
		
	}
	
	
	
	if ( !IS_NPC(ch) )
		--ch->in_room->area->nplayer;
	
	if ( ( obj = get_eq_char( ch, WEAR_LIGHT ) ) != NULL
		&&   obj->item_type == ITEM_LIGHT
		&&   obj->value[2] != 0
		&&   ch->in_room->light > 0 )
		--ch->in_room->light;
 	
	if ( ch == ch->in_room->people )
	{
		ch->in_room->people = ch->next_in_room;
	}
	else
	{
		CHAR_DATA *prev;
		
		for ( prev = ch->in_room->people; prev; prev = prev->next_in_room )
		{
			if ( prev->next_in_room == ch )
			{
				prev->next_in_room = ch->next_in_room;
				break;
			}
		}
		
		if ( prev == NULL )
		{
			bug( "Char_from_room: ch not found.", 0 );
		}
	}
	
	ch->in_room      = NULL;
	ch->next_in_room = NULL;
	return;
}



/*
 * Move a char into a room.
 */
void char_to_room( CHAR_DATA *ch, ROOM_INDEX_DATA *pRoomIndex )
{
	OBJ_DATA *obj;
	
	
	if ( pRoomIndex == NULL )
	{	
		ROOM_INDEX_DATA *room;
		
		bug( "Char_to_room: NULL.", 0 );
		
		if ((room = get_room_index(ROOM_VNUM_TEMPLE)) != NULL)
			char_to_room(ch,room);
		
		return;
	}
	
	
	ch->in_room		= pRoomIndex;
	ch->next_in_room	= pRoomIndex->people;
	pRoomIndex->people	= ch;
	
	
	if ( !IS_NPC(ch) )
	{
		if (ch->in_room->area->empty)
		{
			ch->in_room->area->empty = FALSE;
			ch->in_room->area->age = 0;
		}
		++ch->in_room->area->nplayer;
	}
	
	
	if ( ( obj = get_eq_char( ch, WEAR_LIGHT ) ) != NULL
		&&   obj->item_type == ITEM_LIGHT
		&&   obj->value[2] != 0 )
		++ch->in_room->light;
    //else if ( ( obj = get_eq_char( ch, WEAR_HOLD ) ) != NULL
    //&&   obj->item_type == ITEM_LIGHT
    //&&   obj->value[2] != 0 )
	//++ch->in_room->light;
	
	if (ch->loc_hp[6] > 0 && ch->in_room->blood < 1000) ch->in_room->blood += 1;
	
	return;
}
/*
 * Extract a char from the world.
 */
void extract_char( CHAR_DATA *ch, bool fPull )
{
	CHAR_DATA *wch;
	CHAR_DATA *familiar;
	CHAR_DATA *wizard;
	OBJ_DATA *obj;
	OBJ_DATA *obj_next;
	
	
	if ( ch == NULL ) return;
	
	if ( ch->in_room == NULL )
	{
		bug( "Extract_char: NULL.", 0 );
		return;
	}
	
	if ( fPull )
		die_follower( ch );

	stop_fighting( ch, TRUE );
	
	for ( obj = ch->carrying; obj != NULL; obj = obj_next )
	{
		obj_next = obj->next_content;
		extract_obj( obj );
	}
	
	if (ch->in_room != NULL) 
		char_from_room( ch );
	
	if ( IS_NPC(ch) )
	{
		--ch->pIndexData->count;
		//Clean the Pet Pointer from Master
		if (ch->pet_master != NULL)
		{
			ch->pet_master->pet = NULL;
			ch->pet_master = NULL;
		}
	}
	else if ( ch->pcdata->chobj != NULL )
	{
		ch->pcdata->chobj->chobj = NULL;
		ch->pcdata->chobj = NULL;
	}
	
	if ( !fPull )
	{
		char_to_room( ch, get_room_index( ROOM_VNUM_ALTAR ) );
		return;
	}
	
	if ( ch->desc != NULL && ch->desc->original != NULL )
		do_return( ch, "" );
	
	if (ch->pet != NULL)
	{
	        stop_fighting(ch->pet, TRUE);
		extract_char(ch->pet,TRUE);
		ch->pet = NULL;
	}
	
	
	if (!IS_NPC(ch))
	{
		for ( wch = char_list; wch != NULL; wch = wch->next )
		{
			if ( wch->reply == ch )
				wch->reply = NULL;
			if ( ch->mprog_target == wch )
				wch->mprog_target = NULL;
			
		}
	}	
	if ( ch == char_list )
	{
		char_list = ch->next;
	}
	else
	{
		CHAR_DATA *prev;
		
		for ( prev = char_list; prev != NULL; prev = prev->next )
		{
			if ( prev->next == ch )
			{
				prev->next = ch->next;
				break;
			}
		}
		
		if ( prev == NULL )
		{
			bug( "Extract_char: char not found.", 0 );
			mudsetting->last_proc_logged = 51;
			return;
		}
	}
	if ( (wizard = ch->wizard) != NULL)
	{
		if (!IS_NPC(wizard)) wizard->pcdata->familiar = NULL;
		ch->wizard = NULL;
	}
	if ( !IS_NPC(ch) )
	{
		if ((familiar = ch->pcdata->familiar) != NULL)
		{
			if (IS_NPC(familiar))
			{
				act("...$n slowly fades away to nothing.",familiar,NULL,NULL,TO_ROOM);
				extract_char(familiar,TRUE);
			}
			familiar->wizard = NULL;
			ch->pcdata->familiar = NULL;
		}
		if ((familiar = ch->pcdata->partner) != NULL)
			ch->pcdata->partner = NULL;
		if ((familiar = ch->pcdata->propose) != NULL)
			ch->pcdata->propose = NULL;
		for ( familiar = char_list; familiar != NULL; familiar = familiar->next)
		{
			if ( !IS_NPC(familiar) && familiar->pcdata->propose != NULL && 
				familiar->pcdata->propose == ch )
				familiar->pcdata->propose = NULL;
			if ( !IS_NPC(familiar) && familiar->pcdata->partner != NULL && 
				familiar->pcdata->partner == ch )
				familiar->pcdata->partner = NULL;
		}
	}
	else if (IS_NPC(ch) && ch->lord->len > 1)
	{
		for ( wch = char_list; wch != NULL ; wch = wch->next )
		{
			if (IS_NPC(wch)) continue;
			if (str_cmp(wch->name->str, ch->lord->str)) continue;
			if (wch->pcdata->followers > 0) wch->pcdata->followers--;
		}
	}
	
	if ( ch->desc )
		ch->desc->character = NULL;
	
	free_char( ch );
	mudsetting->last_proc_logged = 52;
	return;
}



/*
 * Find a char in the room.
 */
CHAR_DATA *get_char_room( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *rch;
	int number;
	int count;
	
	number = number_argument( argument, arg );
	count  = 0;
	if ( !str_cmp( arg, "self" ) && (IS_NPC(ch) || ch->pcdata->chobj == NULL))
		return ch;
	for ( rch = ch->in_room->people; rch != NULL; rch = rch->next_in_room )
	{
		if ( !IS_NPC(rch) && IS_HEAD(rch, LOST_HEAD) ) continue;
		else if ( !IS_NPC(rch) && IS_EXTRA(rch, EXTRA_OSWITCH) ) continue;
		else if ( !can_see( ch, rch ) || ( !is_name( arg, rch->name->str ) &&
				!is_name(arg, unknown_name(rch,ch)) &&
				( IS_NPC(rch) || !is_name( arg, rch->morph->str ))))
			continue;
		
		/* so you don't greet your damn self */
		if (!IS_NPC(rch) && is_name(arg, unknown_name(rch,ch)) && rch == ch)
			continue;
		
		if ( ++count == number )
			return rch;
	}
	
	return NULL;
}




/*
 * Find a char in the world.
 */
CHAR_DATA *get_char_world( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *wch;
	int number;
	int count;
	
	if ( ( wch = get_char_room( ch, argument ) ) != NULL )
		return wch;
	
	number = number_argument( argument, arg );
	count  = 0;
	for ( wch = char_list; wch != NULL ; wch = wch->next )
	{
		if ( !IS_NPC(wch) && IS_HEAD(wch, LOST_HEAD) ) continue;
		else if ( !IS_NPC(wch) && IS_EXTRA(wch, EXTRA_OSWITCH) ) continue;
		else if ( !can_see( ch, wch ) || ( !is_name( arg, wch->name->str ) &&
				( IS_NPC(wch) || !is_name( arg, wch->morph->str ))))
			continue;
		if ( ++count == number )
			return wch;
	}
	
	return NULL;
}

CHAR_DATA *get_char_world2( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *wch;
	
	if (argument[0] == '\0') 
		return NULL;
	
	for ( wch = char_list; wch != NULL ; wch = wch->next )
	{
		if ( IS_NPC(wch) && !str_cmp( argument, wch->short_descr->str ) ) 
			return wch;
	}
	
	return NULL;
}
void gain_exp( CHAR_DATA *ch, int gain )
{
	CHAR_DATA *mount = NULL;
	CHAR_DATA *master = NULL;
	
	if ( IS_NPC(ch) && (mount = ch->mount) != NULL && !IS_NPC(mount))
	{
		if ( (master = ch->master) == NULL || master != mount )
			mount->exp += gain;
	}
	if ( !IS_IMMORTAL(ch) )
		ch->exp += gain;
	return;
}



/*
 * Regeneration stuff.
 */
int hit_gain( CHAR_DATA *ch )
{
	double gain;
	double conamount;
	
	//check for linky dead people
        if (!IS_NPC(ch) && ch->desc == NULL)
		return 0;

	if ( IS_NPC(ch) )
	{
		gain = ch->level;
	}
	else
	{
		gain = number_range( 10, 20 );
		
		if ((conamount = (get_curr_con(ch)+1)) > 1)
		{
			switch ( ch->position )
			{
				case POS_MEDITATING: gain *= conamount * 0.5;	break;
				case POS_SLEEPING:   gain *= conamount;		break;
				case POS_RESTING:    gain *= conamount * 0.5;	break;
			}
		}
		
		if ( ch->pcdata->condition[COND_FULL]   == 0 && !IS_HERO(ch) )
			gain *= 0.25;
		
		if ( ch->pcdata->condition[COND_THIRST] == 0 && !IS_HERO(ch) )
			gain *= 0.25;
		
	}
	
        if ( IS_ITEMAFF(ch, ITEMA_REGENERATE) )
        {
            act("{G$n regenerates{x.",ch,NULL,NULL,TO_ROOM);
            act("{GYou regenerate.{x",ch,NULL,NULL,TO_CHAR);
            spell_clot(skill_lookup("clot"), AUTO_REGEN, ch, ch);
            spell_mend(skill_lookup("mend"), AUTO_REGEN, ch, ch);

            if (number_percent() < 50) gain *= 1.20;        /*    50% of a  20% */
            else if (number_percent() < 50) gain *= 1.40;   /*    25% of a  40% */
            else if (number_percent() < 50) gain *= 1.80;   /*  12.5% of a  80% */
            else if (number_percent() < 50) gain *= 2.60;   /*  6.25% of a 160% */
            else if (number_percent() < 50) gain *= 5;      /* 3.125% of a 400% */
        }

	if ( IS_AFFECTED(ch, AFF_POISON) || IS_AFFECTED(ch, AFF_FLAMING))
		gain *= 0.25;

	if ( IS_AFFECTED(ch, AFF_POISON) )
		gain *= 0.25;
	
	if (IS_CLASS(ch,CLASS_MAGE))
	{
		/* if they are tapping the caren, give SUPER Heal! */

		if (IS_SET(ch->act,ACT_TAPPING))
		{
			send_to_char("You feel the life force from the caern enter your body.\n\r",ch);
			gain *= 4;
		}
	}

	if (ch->on != NULL && ch->on->item_type == ITEM_FURNITURE)
	gain = gain * ch->on->value[3] / 90;

   	if (IS_CLASS(ch, CLASS_VAMPIRE)) return 0;
	
	return UMIN((int)gain, ch->max_hit - ch->hit);
}



int mana_gain( CHAR_DATA *ch )
{
	double gain;
	double intamount;
	//
	//check for linky dead people
        if (!IS_NPC(ch) && ch->desc == NULL)
		return 0;
	
	if ( IS_NPC(ch) )
	{
		gain = ch->level;
	}
	else
	{
		if (IS_CLASS(ch, CLASS_VAMPIRE)) return 0;
		gain = number_range( 10, 20 );
		
		if ((intamount = (get_curr_int(ch)+1)) > 1)
		{
			switch ( ch->position )
			{
				case POS_MEDITATING: gain *= intamount * ch->level;	break;
				case POS_SLEEPING:   gain *= intamount;			break;
				case POS_RESTING:    gain *= intamount * 0.5;		break;
			}
		}
		
		if ( !IS_HERO(ch) && ch->pcdata->condition[COND_THIRST] == 0 )
			gain *= 0.25;
		
	}
	
	if ( IS_AFFECTED( ch, AFF_POISON ) || IS_AFFECTED(ch, AFF_FLAMING) )
		gain *= 0.25;

	if ( IS_AFFECTED(ch, AFF_POISON) )
		gain *= 0.25;
	
	if (IS_CLASS(ch,CLASS_MAGE))
	{
		gain *= number_range(8,14);
		
		/* if they are tapping the caren, give SUPER MANA! */

		if (IS_SET(ch->act,ACT_TAPPING))
		{
			send_to_char("You feel the life force from the caern enter your body.\n\r",ch);
			gain *= 4;
		}
	}
	
	if (ch->on != NULL && ch->on->item_type == ITEM_FURNITURE)
		gain = gain * ch->on->value[3] / 90;
	
	return UMIN((int)gain, ch->max_mana - ch->mana);
}		



int move_gain( CHAR_DATA *ch )
{
	double gain;
	double dexamount;
	
	if ( IS_NPC(ch) )
	{
		gain = ch->level;
	}
	else
	{
		if (IS_CLASS(ch, CLASS_VAMPIRE)) return 0;
		gain = number_range( 10, 20 );
		
		if ((dexamount = (get_curr_dex(ch)+1)) > 1)
		{
			switch ( ch->position )
			{
				case POS_MEDITATING: gain *= dexamount * 0.5;	break;
				case POS_SLEEPING:   gain *= dexamount;		break;
				case POS_RESTING:    gain *= dexamount * 0.5;	break;
			}
		}
		
		if ( !IS_HERO(ch) && ch->pcdata->condition[COND_THIRST] == 0 )
			gain *= 0.25;
	}
	
	if ( IS_AFFECTED(ch, AFF_POISON) || IS_AFFECTED(ch, AFF_FLAMING) )
		gain *= 0.25;

	if ( IS_AFFECTED(ch, AFF_POISON) )
		gain *= 0.25;
	
	if (ch->on != NULL && ch->on->item_type == ITEM_FURNITURE)
		gain = gain * ch->on->value[3] / 90;
	
	return UMIN((int)gain, ch->max_move - ch->move);
}



void gain_condition( CHAR_DATA *ch, int iCond, int value )
{
	int condition;

	/*
	 * If the player is in a Imm made safe room.. no thirst
	 */
	if (check_safe_imm(ch))
		return;
	
	if ( value == 0 || IS_NPC(ch) )
		return;
	
	if (!IS_NPC(ch) && IS_HERO(ch) && !IS_CLASS(ch, CLASS_VAMPIRE) 
		&& iCond != COND_DRUNK)
		return;
	
	condition				= ch->pcdata->condition[iCond];
	if (!IS_NPC(ch) && !IS_CLASS(ch, CLASS_VAMPIRE) )
		ch->pcdata->condition[iCond]	= URANGE( 0, condition + value, 50 );
	else
		ch->pcdata->condition[iCond]	= URANGE( 0, condition + value, 100 + ch->pcdata->stats[UNI_BLOOD_MAX]);
	
	if ( ch->pcdata->condition[iCond] == 0 )
	{
		switch ( iCond )
		{
			case COND_FULL:
				if (!IS_CLASS(ch, CLASS_VAMPIRE))
				{
					send_to_char( "You are REALLY hungry.  You become weary and tired.\n\r",  ch );
					ch->move = ch->move - 10;
					act( "You hear $n's stomach rumbling.", ch, NULL, NULL, TO_ROOM );
				}
				break;
				
			case COND_THIRST:
				if (!IS_CLASS(ch, CLASS_VAMPIRE)) 
				{
					send_to_char( "You are REALLY thirsty.  You become weary and tired.\n\r",  ch );
					ch->move = ch->move - 10;
				}
				else if (ch->hit > 0)
				{
					send_to_char( "You are DYING from lack of blood!\n\r", ch );
					act( "$n gets a hungry look in $s eyes.", ch, NULL, NULL, TO_ROOM );
					
					ch->hit -= (int)((double)ch->hit * 0.05);  /* subtract 5% hp */  
/*              ch->hit = ch->hit - number_range(100,300);    */
					if (number_percent() <= ch->beast && ch->beast > 0) vamp_rage(ch);
					if (!IS_VAMPAFF(ch, VAM_FANGS)) power_fangs(ch,ch,"");
					if (number_percent() <= 25 && ch->fighting == NULL)
					{ 
						send_to_char( "Need...more...BLOOD...\n\r", ch );
						do_sleep(ch,"");
						WAIT_STATE( ch, 24 );
					}
				}
				break;
				
			case COND_DRUNK:
				if ( condition != 0 )
					send_to_char( "You are sober.\n\r", ch );
				break;
		}
	}
	else if ( ch->pcdata->condition[iCond] < 10 )
	{
		switch ( iCond )
		{
			case COND_FULL:
				if (!IS_CLASS(ch, CLASS_VAMPIRE)) 
					send_to_char( "You feel hungry.\n\r",  ch );
				break;
				
			case COND_THIRST:
				if (!IS_CLASS(ch, CLASS_VAMPIRE)) 
					send_to_char( "You feel thirsty.\n\r", ch );
				else
				{
					send_to_char( "You crave blood.\n\r", ch );
					if (number_range(1,1000) <= ch->beast && ch->beast > 0) vamp_rage(ch);
					if (number_percent() > (ch->pcdata->condition[COND_THIRST]+75)
						&& !IS_VAMPAFF(ch, VAM_FANGS)) power_fangs(ch,ch,"");
				}
				break;
		}
	}
	
	return;
}