area/
build/testing/
log/
player/
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>
extern GMemChunk *affect_mem_chunk;

AFFECT_DATA *affect_free;

/*
 * Create new Instance of "affect"
 */
AFFECT_DATA *new_affect(void)
{
	static AFFECT_DATA af_zero;
	AFFECT_DATA *af;
	
	if (affect_free == NULL)
		af = g_chunk_new (AFFECT_DATA, affect_mem_chunk);
	else
	{
		af = affect_free;
		affect_free = affect_free->next;
	}
	
	*af = af_zero;
	
	
	VALIDATE(af);
	return af;
}


void free_affect(AFFECT_DATA *af)
{
	if (!IS_VALID(af))
		return;
	
	INVALIDATE(af);
	af->next = affect_free;
	affect_free = af;
}


/*
 * Find the ac value of an obj, including position effect.
 */
int apply_ac( OBJ_DATA *obj, int iWear )
{
	if ( obj->item_type != ITEM_ARMOR )
		return 0;
	
	switch ( iWear )
	{
		case WEAR_BODY:	return 3 * obj->value[0];
		case WEAR_HEAD:	return 2 * obj->value[0];
		case WEAR_LEGS:	return 2 * obj->value[0];
		case WEAR_FEET:	return     obj->value[0];
		case WEAR_HANDS:	return     obj->value[0];
		case WEAR_ARMS:	return     obj->value[0];
		case WEAR_SHIELD:	return     obj->value[0];
		case WEAR_FINGER_L:	return     obj->value[0];
		case WEAR_FINGER_R: return     obj->value[0];
		case WEAR_NECK_1:	return     obj->value[0];
		case WEAR_NECK_2:	return     obj->value[0];
		case WEAR_ABOUT:	return 2 * obj->value[0];
		case WEAR_WAIST:	return     obj->value[0];
		case WEAR_WRIST_L:	return     obj->value[0];
		case WEAR_WRIST_R:	return     obj->value[0];
		case WEAR_HOLD:	return     obj->value[0];
		case WEAR_FACE:	return     obj->value[0];
		case WEAR_SCABBARD_L:return 0;
		case WEAR_SCABBARD_R:return 0;
	}
	
	return 0;
}



/*
 * Apply or remove an affect to a character.
 */
void affect_modify( CHAR_DATA *ch, AFFECT_DATA *paf, bool fAdd )
{
	OBJ_DATA *wield;
	int mod;
	
	mod = paf->modifier;
	
	if ( fAdd )
	{
		SET_BIT( ch->affected_by, paf->bitvector );
	}
	else
	{
		REMOVE_BIT( ch->affected_by, paf->bitvector );
		mod = 0 - mod;
	}
	
	if ( IS_NPC(ch) )
	{
		switch ( paf->location )
		{
			default: break;
			case APPLY_NONE:						break;
			case APPLY_MANA:          ch->max_mana		+= mod;	break;
			case APPLY_HIT:           ch->max_hit		+= mod;	break;
			case APPLY_MOVE:          ch->max_move		+= mod;	break;
			case APPLY_AC:            ch->armor			+= mod;	break;
			case APPLY_HITROLL:       ch->hitroll		+= mod;	break;
			case APPLY_DAMROLL:       ch->damroll		+= mod;	break;
			case APPLY_SAVING_PARA:   ch->saving_throw		+= mod;	break;
			case APPLY_SAVING_ROD:    ch->saving_throw		+= mod;	break;
			case APPLY_SAVING_PETRI:  ch->saving_throw		+= mod;	break;
			case APPLY_SAVING_BREATH: ch->saving_throw		+= mod;	break;
			case APPLY_SAVING_SPELL:  ch->saving_throw		+= mod;	break;
			case APPLY_POLY:	      ch->polyaff		+= mod;	break;
		    case APPLY_BLOOD_MAX:     ch->pcdata->stats[UNI_BLOOD_MAX]	+= mod;	break;
	        case APPLY_BLOOD_POT:     ch->pcdata->stats[UNI_BLOOD_POT]	+= mod;	break;
        }
		return;
	}
	
	if ( IS_CLASS(ch, CLASS_HIGHLANDER) )
	{
		switch ( paf->location )
		{
			default: break;
			case APPLY_NONE:						break;
		}
		return;
	}
	
	switch ( paf->location )
	{
		default:
			bug( "Affect_modify: unknown location %d.", paf->location );
			return;
			
		case APPLY_NONE:						break;
		case APPLY_STR:           ch->pcdata->mod_str	+= mod;	break;
		case APPLY_DEX:           ch->pcdata->mod_dex	+= mod;	break;
		case APPLY_INT:           ch->pcdata->mod_int	+= mod;	break;
		case APPLY_WIS:           ch->pcdata->mod_wis	+= mod;	break;
		case APPLY_CON:           ch->pcdata->mod_con	+= mod;	break;
/*
    case APPLY_SEX:           ch->sex			+= mod;	break;
*/
		case APPLY_SEX:						break;
		case APPLY_CLASS:						break;
		case APPLY_LEVEL:						break;
		case APPLY_AGE:						break;
		case APPLY_HEIGHT:						break;
		case APPLY_WEIGHT:						break;
		case APPLY_MANA:          ch->max_mana		+= mod;	break;
		case APPLY_HIT:           ch->max_hit		+= mod;	break;
		case APPLY_MOVE:          ch->max_move		+= mod;	break;
		case APPLY_GOLD:						break;
		case APPLY_EXP:						break;
		case APPLY_AC:            ch->armor			+= mod;	break;
		case APPLY_HITROLL:       ch->hitroll		+= mod;	break;
		case APPLY_DAMROLL:       ch->damroll		+= mod;	break;
		case APPLY_SAVING_PARA:   ch->saving_throw		+= mod;	break;
		case APPLY_SAVING_ROD:    ch->saving_throw		+= mod;	break;
		case APPLY_SAVING_PETRI:  ch->saving_throw		+= mod;	break;
		case APPLY_SAVING_BREATH: ch->saving_throw		+= mod;	break;
		case APPLY_SAVING_SPELL:  ch->saving_throw		+= mod;	break;
		case APPLY_POLY:	      ch->polyaff		+= mod;	break;
		case APPLY_BLOOD_MAX:     ch->pcdata->stats[UNI_BLOOD_MAX]	+= mod;	break;
	}
	
    /*
     * Check for weapon wielding.
     * Guard against recursion (for weapons with affects).
     */
	if ( ( wield = get_eq_char( ch, WEAR_WIELD ) ) != NULL
		&&   wield->item_type == ITEM_WEAPON
		&&   get_obj_weight(wield) > str_app[get_curr_str(ch)].wield )
	{
		static int depth;
		
		if ( depth == 0 )
		{
			depth++;
			act( "You drop $p.", ch, wield, NULL, TO_CHAR );
			act( "$n drops $p.", ch, wield, NULL, TO_ROOM );
			obj_from_char( wield );
			obj_to_room( wield, ch->in_room );
			depth--;
		}
	}
	
	return;
}

void affect_remove_obj( OBJ_DATA *obj, AFFECT_DATA *paf)
{
	int where, vector;
	if ( obj->affected == NULL )
	{
		bug( "Affect_remove_object: no affect.", 0 );
		return;
	}
	
	obj->value[0] = 0;
	if (obj->carried_by != NULL && obj->wear_loc != -1)
		affect_modify( obj->carried_by, paf, FALSE );
	
	where = paf->where;
	vector = paf->bitvector;
	
    /* remove flags from the object if needed */
	if (paf->bitvector)
		switch( paf->where)
		{
			case TO_OBJECT:
				REMOVE_BIT(obj->extra_flags,paf->bitvector);
				break;
			case TO_WEAPON:
				if (obj->item_type == ITEM_WEAPON)
					REMOVE_BIT(obj->value[4],paf->bitvector);
				obj->value[0] = 0;
				break;
		}
		
	if ( paf == obj->affected )
	{
		obj->affected    = paf->next;
	}
	else
	{
		AFFECT_DATA *prev;
		
		for ( prev = obj->affected; prev != NULL; prev = prev->next )
		{
			if ( prev->next == paf )
			{
				prev->next = paf->next;
				break;
			}
		}
		
		if ( prev == NULL )
		{
			bug( "Affect_remove_object: cannot find paf.", 0 );
			return;
		}
	}
	
	free_affect(paf);
	
	if (obj->carried_by != NULL && obj->wear_loc != -1)
		return;
}

/* give an affect to an object */
void affect_to_obj(OBJ_DATA *obj, AFFECT_DATA *paf)
{
	AFFECT_DATA *paf_new;
	
	paf_new		= new_affect();
	*paf_new        = *paf;
	paf_new->next	= obj->affected;
	obj->affected	= paf_new;
	
    /* apply any affect vectors to the object's extra_flags 
    if (paf->bitvector)
        switch (paf->where)
        {
        case TO_OBJECT:
    	    SET_BIT(obj->extra_flags,paf->bitvector);
	    break;
        case TO_WEAPON:
	    if (obj->item_type == ITEM_WEAPON)
	        SET_BIT(obj->value[4],paf->bitvector);
	    break;
        }
    
    */
	return;
}


/*
 * Give an affect to a char.
 */
void affect_to_char( CHAR_DATA *ch, AFFECT_DATA *paf )
{
	AFFECT_DATA *paf_new;
	
	paf_new		= new_affect();
	*paf_new        = *paf;
	paf_new->next	= ch->affected;
	ch->affected	= paf_new;
	
	affect_modify( ch, paf_new, TRUE );
	return;
}


void affect_modify_room( ROOM_INDEX_DATA *room, AFFECT_DATA *paf, bool fAdd )
{
	if ( fAdd )
		SET_BIT( room->affected_by, paf->bitvector );
	else
		REMOVE_BIT( room->affected_by, paf->bitvector );
	return;
}

/*give affect to room YEA BUDDIE! Spiral in da HOUSE! */
void affect_to_room( ROOM_INDEX_DATA *room, AFFECT_DATA *paf )
{
	AFFECT_DATA *paf_new;
	
	paf_new		= new_affect();
	*paf_new        = *paf;
	paf_new->next	= room->affected;
	room->affected	= paf_new;
	
	affect_modify_room( room, paf_new, TRUE );
	return;
}


void affect_remove_room( ROOM_INDEX_DATA *room, AFFECT_DATA *paf )
{   
	if ( room->affected == NULL )
	{
		bug( "Affect_remove: no affect.", 0 );
		return;
	}
	
	affect_modify_room( room, paf, FALSE );
	
	if ( paf == room->affected )
	{
		room->affected	= paf->next;
	}
	else
	{
		AFFECT_DATA *prev;
		
		for ( prev = room->affected; prev != NULL; prev = prev->next )
		{
			if ( prev->next == paf )
			{
				prev->next = paf->next;
				break;
			}
		}
		
		if ( prev == NULL )
		{
			bug( "Affect_remove: cannot find paf.", 0 );
			return;
		}
	}
	
	free_affect(paf);
	return;
}


/*
 * Remove an affect from a char.
 */
void affect_remove( CHAR_DATA *ch, AFFECT_DATA *paf )
{
	if ( ch->affected == NULL )
	{
		bug( "Affect_remove: no affect.", 0 );
		return;
	}
	
	affect_modify( ch, paf, FALSE );
	
	if ( paf == ch->affected )
	{
		ch->affected	= paf->next;
	}
	else
	{
		AFFECT_DATA *prev;
		
		for ( prev = ch->affected; prev != NULL; prev = prev->next )
		{
			if ( prev->next == paf )
			{
				prev->next = paf->next;
				break;
			}
		}
		
		if ( prev == NULL )
		{
			bug( "Affect_remove: cannot find paf.", 0 );
			return;
		}
	}
	
	free_affect(paf);	
	return;
}



/*
 * Strip all affects of a given sn.
 */
void affect_strip( CHAR_DATA *ch, int sn )
{
	AFFECT_DATA *paf;
	AFFECT_DATA *paf_next;
	
	for ( paf = ch->affected; paf != NULL; paf = paf_next )
	{
		paf_next = paf->next;
		if ( paf->type == sn )
			affect_remove( ch, paf );
	}
	
	return;
}




/*
 * Return true if a char is affected by a spell.
 */
bool is_affected( CHAR_DATA *ch, int sn )
{
	AFFECT_DATA *paf;
	
	for ( paf = ch->affected; paf != NULL; paf = paf->next )
	{
		if ( paf->type == sn )
			return TRUE;
	}
	
	return FALSE;
}




/*
 * Add or enhance an affect.
 */
void affect_join( CHAR_DATA *ch, AFFECT_DATA *paf )
{
	AFFECT_DATA *paf_old;
	bool found;
	
	found = FALSE;
	for ( paf_old = ch->affected; paf_old != NULL; paf_old = paf_old->next )
	{
		if ( paf_old == NULL )
			return;
		
		if ( paf_old->type == paf->type )
		{
			paf->duration += paf_old->duration;
			paf->modifier += paf_old->modifier;
			affect_remove( ch, paf_old );
			break;
		}
	}
	
	affect_to_char( ch, paf );
	return;
}

/*
 * Return ascii name of an item type.
 */
char *item_type_name( OBJ_DATA *obj )
{
	switch ( obj->item_type )
	{
		case ITEM_LIGHT:		return "light";
		case ITEM_SCROLL:		return "scroll";
		case ITEM_WAND:		return "wand";
		case ITEM_STAFF:		return "staff";
		case ITEM_WEAPON:		return "weapon";
		case ITEM_TREASURE:		return "treasure";
		case ITEM_ARMOR:		return "armor";
		case ITEM_POTION:		return "potion";
		case ITEM_FURNITURE:	return "furniture";
		case ITEM_TRASH:		return "trash";
		case ITEM_CONTAINER:	return "container";
		case ITEM_DRINK_CON:	return "drink container";
		case ITEM_KEY:		return "key";
		case ITEM_FOOD:		return "food";
		case ITEM_MONEY:		return "money";
		case ITEM_BOAT:		return "boat";
		case ITEM_CORPSE_NPC:	return "npc corpse";
		case ITEM_CORPSE_PC:	return "pc corpse";
		case ITEM_FOUNTAIN:		return "fountain";
		case ITEM_PILL:		return "pill";
		case ITEM_PORTAL:		return "portal";
		case ITEM_EGG:		return "egg";
		case ITEM_VOODOO:		return "voodoo doll";
		case ITEM_STAKE:		return "stake";
		case ITEM_MISSILE:		return "missile";
		case ITEM_AMMO:		return "ammo";
		case ITEM_QUEST:		return "quest token";
		case ITEM_QUESTCARD:	return "quest card";
		case ITEM_QUESTMACHINE:	return "quest generator";
		case ITEM_SYMBOL:		return "magical symbol";
		case ITEM_BOOK:		return "book";
		case ITEM_PAGE:		return "page";
		case ITEM_TOOL:		return "tool";
		case ITEM_COOKIE:	return "cookie";
		case ITEM_TFILET:	return "filet";
		case ITEM_FIRE:		return "fire";
	}
	
	bug( "Item_type_name: unknown type %d.", obj->item_type );
	return "(unknown)";
}




/*
 * Return ascii name of an affect location.
 */
char *affect_loc_name( int location )
{
	switch ( location )
	{
		case APPLY_NONE:		return "none";
		case APPLY_STR:		return "strength";
		case APPLY_DEX:		return "dexterity";
		case APPLY_INT:		return "intelligence";
		case APPLY_WIS:		return "wisdom";
		case APPLY_CON:		return "constitution";
		case APPLY_SEX:		return "sex";
		case APPLY_CLASS:		return "class";
		case APPLY_LEVEL:		return "level";
		case APPLY_AGE:		return "age";
		case APPLY_MANA:		return "mana";
		case APPLY_HIT:		return "hp";
		case APPLY_MOVE:		return "moves";
		case APPLY_GOLD:		return "gold";
		case APPLY_EXP:		return "experience";
		case APPLY_AC:		return "armor class";
		case APPLY_HITROLL:		return "hit roll";
		case APPLY_DAMROLL:		return "damage roll";
		case APPLY_SAVING_PARA:	return "save vs paralysis";
		case APPLY_SAVING_ROD:	return "save vs rod";
		case APPLY_SAVING_PETRI:	return "save vs petrification";
		case APPLY_SAVING_BREATH:	return "save vs breath";
		case APPLY_SAVING_SPELL:	return "save vs spell";
		case APPLY_POLY:		return "polymorph form";
	    case APPLY_BLOOD_MAX:     return "Blood Max";
	    case APPLY_BLOOD_POT:     return "Blood Potence";
    }
	
	bug( "Affect_location_name: unknown location %d.", location );
	return "(unknown)";
}


AFFECT_DATA *find_affect( CHAR_DATA *ch, int bitvector)
{
	
	AFFECT_DATA *paf;
	AFFECT_DATA *paf_next;
    
	for ( paf = ch->affected; paf != NULL; paf = paf_next )
	{
		paf_next	= paf->next;
		if ( paf->bitvector == bitvector )
			return paf;
	}
	return NULL;
}