/
mudtem/
mudtem/area/scripts/
mudtem/bin/
mudtem/log/
mudtem/player/
mudtem/slang/autoconf/
mudtem/slang/doc/
mudtem/slang/doc/OLD/help/
mudtem/slang/doc/internal/
mudtem/slang/doc/text/
mudtem/slang/doc/tm/tools/
mudtem/slang/examples/
mudtem/slang/modules/
mudtem/slang/slsh/
mudtem/slang/slsh/lib/
mudtem/slang/slsh/scripts/
mudtem/slang/src/mkfiles/
mudtem/slang/src/util/
mudtem/src/CVS/
mudtem/src/include/
mudtem/src/include/CVS/
mudtem/src/var/CVS/
#include "include.h"
#include "command.h"
#include "smart.h"
#include "events.h"
#include "recycle.h"

bool pc_in_room(ROOM_INDEX_DATA *, CHAR_DATA *);
bool can_cast_spell(CHAR_DATA *, int);

int spell_dam_mage( CHAR_DATA *, CHAR_DATA * );
int spell_aff_mage( CHAR_DATA *, CHAR_DATA * );

#if !defined(USAR_MACROS)
bool is_mob_safe( CHAR_DATA *ch )
{
	if ( ch->in_room == NULL )
		return TRUE;

	if ( IS_SET(ch->in_room->room_flags, ROOM_SAFE)
	||   IS_SET(ch->in_room->room_flags, ROOM_PET_SHOP) )
		return TRUE;

	if ( ch->pIndexData->pShop != NULL
	||   ch->pIndexData->pRepair != NULL )
		return TRUE;

	if ( IS_SET(ch->act, ACT_IS_HEALER)
	||   IS_SET(ch->act, ACT_PRACTICE)
	||   IS_SET(ch->act, ACT_TRAIN)
	||   IS_SET(ch->act, ACT_IS_CHANGER)
	||   IS_SET(ch->act, ACT_BANKER)
	||   IS_SET(ch->act, ACT_PROTOTIPO) )
		return TRUE;

	return FALSE;
}
#endif

bool can_cast( CHAR_DATA *ch, int sn, int clase )
{
	if ( sn < 1 )
	{
		bugf( "can_cast : spell %d invalido", sn );
		return FALSE;
	}

	if ( IS_SET(ch->in_room->room_flags, ROOM_CONE_OF_SILENCE)
	&&   clase != CLASS_PSI )
		return FALSE;

	return (mana_cost(sn, getNivelPr(ch), clase) < ch->mana);
}

bool can_disarm( CHAR_DATA *ch, CHAR_DATA *victim )
{
	OBJ_DATA *weapon;

	if ( get_eq_char(ch, WEAR_WIELD) == NULL
	&&   get_skill(ch, gsn_hand_to_hand) == 0 )
		return FALSE;

	if ( (weapon = get_eq_char(victim, WEAR_WIELD)) == NULL
	 &&  (weapon = get_eq_char(victim, WEAR_SECONDARY)) == NULL )
		return FALSE;

	if ( IS_OBJ_STAT(weapon, ITEM_NOREMOVE) )
		return FALSE;

	return TRUE;
}

#if !defined(USAR_MACROS)
bool can_circle( CHAR_DATA *ch, CHAR_DATA *victim )
{
	if ( IS_NPC(ch) && get_eq_char(ch, WEAR_WIELD) == NULL )
		return FALSE;

	if ( victim->fighting == ch )
		return FALSE;

	return TRUE;
}
#endif

int count_friends( CHAR_DATA *ch, CHAR_DATA *victim )
{
	CHAR_DATA *gch;
	int cnt = 0;

	for ( gch = ch->in_room->people; gch; gch = gch->next_in_room )
		if ( gch != ch && gch->fighting == victim )
			cnt++;

	return cnt;
}

bool will_flee( CHAR_DATA *ch, CHAR_DATA *victim )
{
	int chance = (getNivelPr(victim) - getNivelPr(ch))*5;

	if ( IS_AFFECTED2(ch, AFF_HOLD) )
		return FALSE;

	if ( IS_MOB_CASTER(ch)
	&&   IS_SET(ch->in_room->room_flags, ROOM_NOMAGIC) )
		return TRUE;

	if ( ch->hit < (ch->max_hit / 4)
	&&   IS_SET(ch->act, ACT_WIMPY) )
		chance += 20;

	if ( IS_MOB_CASTER(ch) && ch->mana < ch->max_mana / 6 )
		chance += 20;

	if ( IS_MOB_MAGIC(ch) && !CAN_SAY(ch) )
		chance += 30;

	if ( ES_THIEF(ch)
	&&   ch->hit < ch->max_hit / 3 )
		chance += 20;

	if ( ch->hit > ch->max_hit / 2 )
		chance -= 50;

	if ( IS_AFFECTED(ch, AFF_SANCTUARY) )
		chance -= 10;
	else
		chance += 10;

	if ( IS_AFFECTED(victim, AFF_SANCTUARY) )
		chance += 10;
	else
		chance -= 10;

	if ( victim->hit > victim->max_hit / 2 )
		chance += getNivelPr(victim) - getNivelPr(ch);

	if ( ES_WARRIOR(ch) )
		chance /= 2;

	if ( IS_SET(ch->act, ACT_SENTINEL) )
		chance /= 2;

	if ( ES_THIEF(ch)
	&&   count_friends(ch, victim) > 0 )
		chance /= (count_friends(ch,victim) + 1);

	return CHANCE(chance);
}

void mob_fight( EVENT *ev )
{
	CHAR_DATA *ch = ev->item.ch;
	CHAR_DATA *victim = get_char_id_room( ch, (long) ev->param );

	if ( !victim || !ch->fighting )
		return;

	if ( ch->wait )
	{
		char_event_add( ch, ch->wait, (void *) victim->id, mob_fight );
		return;
	}

	if ( ch->position == POS_RESTING )
	{
		do_stand( ch, "" );
		char_event_add( ch, 1, (void *) victim->id, mob_fight );
		return;
	}

	if ( IS_AFFECTED2(ch, AFF_HOLD)
	&&   CHANCE(getNivelPr(ch)) )
	{
		do_untangle(ch, "");
		char_event_add( ch, ch->wait, (void *) victim->id, mob_fight );
		return;
	}

	switch(getClasePr(ch))
	{
		case CLASS_WARRIOR:	act_warrior(ch, victim);	break;
		case CLASS_THIEF:	act_thief(ch, victim);		break;
		case CLASS_MAGE:	act_mage(ch, victim);		break;
		case CLASS_CLERIC:	act_cleric(ch, victim);		break;
		case CLASS_PSI:		act_psi(ch, victim);		break;
	}

	if ( !char_died(ch) && !event_pending(ch->events, mob_fight) )
		char_event_add( ch, ch->wait ? ch->wait : 1, (void *) victim->id, mob_fight );
}

void act_mage( CHAR_DATA *ch, CHAR_DATA *victim )
{
	int spell = -1;
	char buf[MIL];

	if ( !IS_PET(ch)
	&&  ((ch->hit > ch->max_hit / 2) || CHANCE(20)) )
		spell = spell_aff_mage(ch, victim);

	if ( spell == -1 )
		spell = spell_dam_mage(ch, victim);

	if ( spell > 0 && CAN_SAY(ch) )
	{
		sprintf( buf, "'%s'", skill_table[spell].name );
		do_cast( ch, buf );
		return;
	}

	if ( ES_WARRIOR(ch) )
		act_warrior( ch, victim );
	else
	if ( ES_THIEF(ch) )
		act_thief( ch, victim );
	else
	if ( will_flee(ch, victim) )
	{
		do_flee( ch, "" );
		if ( ch->position == POS_STANDING )
		{
			if ( !IS_AFFECTED(ch, AFF_SNEAK) )
				do_sneak( ch, "" );
			if ( !IS_AFFECTED(ch, AFF_HIDE) )
				do_hide( ch, "" );
			if ( IS_MOB_CASTER(ch) )
			{
				if ( can_cast_spell( ch, gsn_teleport ) )
				{
					sprintf( buf, "teleport %s", ch->name );
					do_cast( ch, buf ); /* mejor perderse */
				}
				else
				if ( can_cast_spell( ch, gsn_invis ) )
					do_cast( ch, "invisibility" );
			}
		}
	}
}

void act_cleric( CHAR_DATA *ch, CHAR_DATA *victim )
{
	char buf[MIL];
	int spell = 0;

	if ( ch->hit < ch->max_hit / 2
	||   victim->hit < victim->max_hit / 2
	||   CHANCE(getNivelPr(ch)) )
	{
		if (((ES_WARRIOR(ch) && getNivelPr(ch) > 22)
		 ||   getNivelPr(ch) > 20)
		&&   ch->hit + 100 < ch->max_hit
		&&   can_cast( ch, gsn_heal, CLASS_CLERIC )
		&&   CHANCE(50) )
			spell = gsn_heal;
		else
		if ( getNivelPr(ch) > 35
		&&   ch->hit < ch->max_hit / 4
		&&  !IS_NEUTRAL(ch)
		&& ( (IS_GOOD(ch) && IS_EVIL(victim))
		  || (IS_EVIL(ch) && IS_GOOD(victim)) )
		&&   can_cast( ch, gsn_holy_word, CLASS_CLERIC )
		&&   CHANCE(80) )
			spell = gsn_holy_word;
		else
		if ( getNivelPr(ch) > 34
		&&   IS_GOOD(ch)
		&&  !IS_GOOD(victim)
		&&   can_cast( ch, gsn_ray_of_truth, CLASS_CLERIC )
		&&   CHANCE(80) )
			spell = gsn_ray_of_truth;
		else
		if ( getNivelPr(ch) > 33
		&&   IS_EVIL(ch)
		&&   can_cast( ch, gsn_demonfire, CLASS_CLERIC )
		&&   CHANCE(70) )
			spell = gsn_demonfire;
		else
		if ( getNivelPr(ch) > 19
		&&  !ES_IMMUNE(victim, IMM_FIRE)
		&&   can_cast( ch, gsn_flamestrike, CLASS_CLERIC )
		&&   CHANCE(60) )
			spell = gsn_flamestrike;
		else
		if ( getNivelPr(ch) > 17
		&&   IS_OUTSIDE(ch)
		&&   weather_info.sky >= SKY_RAINING
		&&   can_cast( ch, gsn_call_lightning, CLASS_CLERIC )
		&&   CHANCE(70) )
			spell = gsn_call_lightning;
		else
		if ( IS_EVIL(victim)
		&&   getNivelPr(ch) > 15
		&&   can_cast( ch, gsn_dispel_evil, CLASS_CLERIC )
		&&   CHANCE(50) )
			spell = gsn_dispel_evil;
		else
		if ( IS_GOOD(victim)
		&&   getNivelPr(ch) > 15
		&&   can_cast( ch, gsn_dispel_good, CLASS_CLERIC )
		&&   CHANCE(50) )
			spell = gsn_dispel_good;
		else
		if ( getNivelPr(ch) > 22
		&&   can_cast( ch, gsn_lightning_bolt, CLASS_CLERIC )
		&&   CHANCE(60) )
			spell = gsn_lightning_bolt;
		else
		if ( getNivelPr(ch) > 22
		&&   can_cast( ch, gsn_harm, CLASS_CLERIC )
		&&   CHANCE(60) )
			spell = gsn_harm;
		else
		if ( getNivelPr(ch) > 12
		&&   can_cast( ch, gsn_cause_critical, CLASS_CLERIC )
		&&   CHANCE(60) )
			spell = gsn_cause_critical;
		else
		if ( getNivelPr(ch) > 9
		&&   can_cast( ch, gsn_earthquake, CLASS_CLERIC )
		&&   CHANCE(60) )
			spell = gsn_earthquake;
		else
		if ( getNivelPr(ch) > 6
		&&   can_cast( ch, gsn_cause_serious, CLASS_CLERIC )
		&&   CHANCE(60) )
			spell = gsn_cause_serious;
		else
		if ( can_cast(ch, gsn_cause_light, CLASS_CLERIC) )
			spell = gsn_cause_light;
	}
	else
	{
		if ( !IS_AFFECTED2(victim, AFF_MUTE)
		&&   getNivelPr(ch) > 18
		&&  !saves_spell(getNivelPr(ch), victim, DAM_OTHER)
		&&  (es_caster(victim) || CHANCE(getNivelPr(victim)/2))
		&&   can_cast( ch, gsn_mute, CLASS_CLERIC ) )
			spell = gsn_mute;
		else
		if ( !IS_AFFECTED(victim, AFF_FAERIE_FIRE)
		&&    getNivelPr(ch) > 2
		&&    can_cast( ch, gsn_faerie_fire, CLASS_CLERIC )
		&&    CHANCE(90) )
			spell = gsn_faerie_fire;
		else
		if ( getNivelPr(ch) > 23
		&& ( IS_AFFECTED(victim, AFF_SANCTUARY)
		 || (IS_AFFECTED(victim, AFF_HASTE) && (!IS_NPC(victim) || !IS_SET(victim->off_flags, OFF_FAST)))
		 || (IS_AFFECTED(victim, AFF_PROTECT_EVIL) && IS_EVIL(ch))
		 || (IS_AFFECTED(victim, AFF_PROTECT_GOOD) && IS_GOOD(ch)))
		&&  !saves_spell(getNivelPr(ch), victim, DAM_OTHER)
		&&   can_cast( ch, gsn_dispel_magic, CLASS_CLERIC ) )
			spell = gsn_dispel_magic;
		else
		if ( getNivelPr(ch) > 16
		&&   victim->carrying
		&&  !saves_spell(getNivelPr(ch), victim, DAM_FIRE)
		&&   CHANCE(70)
		&&   can_cast( ch, gsn_heat_metal, CLASS_CLERIC ) )
			spell = gsn_heat_metal;
		else
		if ( !IS_AFFECTED(victim, AFF_BLIND)
		&&   getNivelPr(ch) > 7
		&&  !saves_spell(getNivelPr(ch), victim, DAM_LIGHT)
		&&   CHANCE(80)
		&&   can_cast( ch, gsn_blindness, CLASS_CLERIC ) )
			spell = gsn_blindness;
		else
		if ( getNivelPr(ch) > 30
		&&  !IS_AFFECTED(victim, AFF_SLOW)
		&&   CHANCE(40)
		&&   can_cast( ch, gsn_slow, CLASS_CLERIC )
		&&  !saves_spell(getNivelPr(ch), victim, DAM_OTHER) )
			spell = gsn_slow;
		else
		if ( !IS_AFFECTED(victim, AFF_PLAGUE)
		&&    getNivelPr(ch) > 16
		&&    can_cast( ch, gsn_plague, CLASS_CLERIC )
		&&   !saves_spell(getNivelPr(ch), victim, DAM_DISEASE)
		&&    CHANCE(60) )
			spell = gsn_plague;
		else
		if ( !IS_AFFECTED(victim, AFF_POISON)
		&&    getNivelPr(ch) > 12
		&&    can_cast( ch, gsn_poison, CLASS_CLERIC )
		&&   !saves_spell(getNivelPr(ch), victim, DAM_POISON)
		&&    CHANCE(60) )
			spell = gsn_poison;
		else
		if ( !IS_AFFECTED2(victim, AFF_ESTUPIDEZ)
		&&    getNivelPr(ch) > 25
		&&    can_cast( ch, gsn_estupidez, CLASS_CLERIC )
		&&   !saves_spell(getNivelPr(ch), victim, DAM_MENTAL)
		&&    CHANCE(30) )
			spell = gsn_estupidez;
		else
		if ( !IS_AFFECTED(victim, AFF_CURSE)
		&&   getNivelPr(ch) > 17
		&&   can_cast( ch, gsn_curse, CLASS_CLERIC )
		&&   CHANCE(60) )
			spell = gsn_curse;
		else
		if ( !IS_AFFECTED(victim, AFF_CALM)
		&&    getNivelPr(ch) > 29
		&&    can_cast( ch, gsn_calm, CLASS_CLERIC )
		&&    CHANCE(50) )
			spell = gsn_calm;
		else
		if ( can_cast(ch, gsn_cause_light, CLASS_CLERIC) )
			spell = gsn_cause_light;
	}

	if (spell < 0)
	{
		bugf( "Act_cleric : spell %d invalido", spell );
		return;
	}

	if ( spell > 0 && CAN_SAY(ch) )
	{
		sprintf(buf,"'%s'", skill_table[spell].name );
		do_cast( ch, buf );
		return;
	}

	if ( ES_WARRIOR(ch) || ES_THIEF(ch) )
		while(TRUE)
			switch(number_range(0,1))
			{
				case 0:	if ( ES_WARRIOR(ch) )
					{
						act_warrior(ch, victim);
						return;
					}
					break;
				case 1: if ( ES_THIEF(ch) )
					{
						act_thief(ch, victim);
						return;
					}
					break;
			}

	if ( will_flee(ch, victim) )
		do_flee( ch, "" );
}

void act_warrior( CHAR_DATA *ch, CHAR_DATA *victim )
{
	switch( number_range(0,4) )
	{
		case 0:
		if ( IS_PART(ch, PART_TAIL)
		&&   victim->position >= POS_FIGHTING )
		{
			do_tail( ch, "" );
			return;
		}
		break;

		case 1:
		if ( !IS_AFFECTED(ch, AFF_BERSERK)
		&&   !IS_AFFECTED(ch, AFF_CALM)
		&&    ch->mana > 50
		&&    IS_SET(ch->off_flags, OFF_BERSERK) )
		{
			do_berserk( ch, "" );
			return;
		}
		break;

		case 2:
		if ( IS_SET(ch->off_flags, OFF_DISARM)
		&&   can_disarm(ch, victim) )
		{
			do_disarm( ch, "" );
			return;
		}
		break;

		case 3:
		if ( IS_SET(ch->off_flags, OFF_BASH)
		&&   victim->position >= POS_FIGHTING )
		{
			do_bash( ch, "" );
			return;
		}
		break;

		case 4:
		if ( IS_SET(ch->off_flags, OFF_KICK) )
		{
			do_kick( ch, "" );
			return;
		}
		break;
	}

	if ( ES_THIEF(ch) )
		act_thief( ch, victim );
	else
	if ( will_flee(ch, victim) )
		do_flee( ch, "" );
}

void act_thief( CHAR_DATA *ch, CHAR_DATA *victim )
{
	switch(number_range(0,5))
	{
		case 0:
		if ( IS_SET(ch->off_flags, OFF_CIRCLE)
		&&   can_circle(ch, victim)
		&& (!IS_PET(ch) || IS_NPC(victim)) )
		{
			do_circle( ch, "" );
			return;
		}
		break;

		case 1:
		if ( !IS_AFFECTED2(victim, AFF_HOLD)
		&&   !IS_SET(victim->form, FORM_ANIMAL)
		&&   !IS_PET(ch) )
		{
			do_snare( ch, "" );
			return;
		}
		break;

		case 2:
		if ( victim->position >= POS_FIGHTING
		&&  !IS_AFFECTED(victim, AFF_FLYING)
		&&   IS_SET(ch->off_flags, OFF_TRIP) )
		{
			do_trip( ch, "" );
			return;
		}
		break;

		case 3:
		if ( !IS_AFFECTED(victim, AFF_BLIND)
		&&    IS_SET(ch->off_flags, OFF_KICK_DIRT)
		&&   !IS_PET(ch) )
		{
			do_dirt( ch, "" );
			return;
		}
		break;

		case 4:
		if ( IS_SET(ch->off_flags, OFF_KICK) )
		{
			do_kick( ch, "" );
			return;
		}
		break;

		case 5:
		if ( IS_SET(ch->off_flags, OFF_DISARM)
		&&   can_disarm(ch, victim) )
		{
			do_disarm( ch, "" );
			return;
		}
		break;
	}

	if ( will_flee(ch, victim) )
		do_flee( ch, "" );
}

void act_psi( CHAR_DATA *ch, CHAR_DATA *victim )
{
	int spell = 0;
	char buf[MIL];

	if ( getNivelPr(ch) > 29
	&&   IS_EVIL(ch)
	&&   can_cast( ch, gsn_death_field, CLASS_PSI )
	&&   CHANCE(40) )
		spell = gsn_death_field;
	else
	if ( getNivelPr(ch) > 29
	&&   can_cast( ch, gsn_hellspawn, CLASS_PSI )
	&&   CHANCE(80) )
		spell = gsn_hellspawn;
	else
	if ( getNivelPr(ch) > 24
	&&   can_cast( ch, gsn_ultrablast, CLASS_PSI )
	&&   CHANCE(80) )
		spell = gsn_ultrablast;
	else
	if ( getNivelPr(ch) > 19
	&&   can_cast( ch, gsn_detonate, CLASS_PSI )
	&&   CHANCE(80) )
		spell = gsn_detonate;
	else
	if ( getNivelPr(ch) > 16
	&&   can_cast( ch, gsn_psionic_blast, CLASS_PSI )
	&&   CHANCE(80) )
		spell = gsn_psionic_blast;
	else
	if ( getNivelPr(ch) > 13
	&&   can_cast( ch, gsn_energy_drain, CLASS_PSI )
	&&   CHANCE(80) )
		spell = gsn_energy_drain;
	else
	if ( getNivelPr(ch) > 12
	&&   can_cast( ch, gsn_ego_whip, CLASS_PSI )
	&&   CHANCE(80) )
		spell = gsn_ego_whip;
	else
	if ( getNivelPr(ch) > 8
	&&   can_cast( ch, gsn_project_force, CLASS_PSI )
	&&   CHANCE(75) )
		spell = gsn_project_force;
	else
	if ( getNivelPr(ch) > 7
	&&   can_cast( ch, gsn_psychic_crush, CLASS_PSI )
	&&   CHANCE(75) )
		spell = gsn_psychic_crush;
	else
	if ( getNivelPr(ch) > 5
	&&   can_cast( ch, gsn_agitation, CLASS_PSI )
	&&   CHANCE(75) )
		spell = gsn_agitation;
	else
	if ( getNivelPr(ch) > 3
	&&   can_cast( ch, gsn_psychic_drain, CLASS_PSI )
	&&   CHANCE(75) )
		spell = gsn_psychic_drain;
	else
	if ( can_cast( ch, gsn_mind_thrust, CLASS_PSI ) )
		spell = gsn_mind_thrust;

	if (spell < 0)
	{
		bugf( "Act_psi : spell %d invalido", spell );
		return;
	}

	if (spell > 0)
	{
		sprintf(buf,"'%s'", skill_table[spell].name );
		do_cast( ch, buf );
		return;
	}

	if ( ES_WARRIOR(ch) )
		act_warrior( ch, victim );
	else
	if ( ES_THIEF(ch) )
		act_thief( ch, victim );
	else
	if ( will_flee(ch, victim) )
		do_flee( ch, "" );
}

MF_DATA *mfd_list;

bool is_mob_fighting( CHAR_DATA *ch )
{
	MF_DATA *mfd;

	for ( mfd = mfd_list; mfd; mfd = mfd->next )
		if ( mfd->mob == ch )
			return TRUE;

	return FALSE;
}

void stop_mob_fight( CHAR_DATA *ch )
{
	MF_DATA *mfd, *prev;

	if ( mfd_list == NULL )
	{
		bug( "Stop_mob_fight : mfd_list NULL, mob %d", ch->pIndexData->vnum );
		return;
	}

	if ( !is_mob_fighting(ch) )
	{
		bug( "Stop_mob_fight : mob %d no esta peleando", ch->pIndexData->vnum );
		return;
	}

	if ( mfd_list->mob == ch )
	{
		mfd		= mfd_list;
		mfd_list	= mfd_list->next;
		free_mfd(mfd);
	}
	else
	{
		for ( prev = mfd_list; prev; prev = prev->next )
			if ( prev->next && prev->next->mob == ch )
				break;

		if ( !prev )
		{
			bug( "Stop_mob_fight : prev NULL, mob %d", ch->pIndexData->vnum );
			return;
		}

		mfd		= prev->next;
		prev->next	= mfd->next;
		free_mfd( mfd );
	}
}

void set_mob_fight( CHAR_DATA *ch )
{
	MF_DATA *mfd;

	mfd		= new_mfd();
	mfd->mob	= ch;
	mfd->next	= mfd_list;
	mfd_list	= mfd;
}

void mf_update( void )
{
	MF_DATA *mfd;

	for ( mfd = mfd_list; mfd; mfd = mfd->next )
	{
		if ( mfd->mob->wait > 0 )
			mfd->mob->wait--;
		if ( mfd->mob->daze > 0 )
			mfd->mob->daze--;
	}
}

int getmin( int *arr, int n )
{
	int x = 100, j, k = -1;

	for ( j = 0; j < n; ++j )
		if ( x == -1 || x > arr[j] )
		{
			k = j;
			x = arr[j];
		}

	return k;
}

bool can_cast_spell( CHAR_DATA *ch, int sn )
{
	static int levarr[5];
	int levmage	= LEVEL_HERO,
	    levpsi	= LEVEL_HERO,
	    levcleric	= LEVEL_HERO,
	    levwar	= LEVEL_HERO,
	    levth	= LEVEL_HERO,
	    clase, level, cual;

	if ( sn < 1 )
	{
		bugf( "Can_cast_spell : spell %d inexistente", sn );
		return FALSE;
	}

	if ( is_affected(ch, sn) )
		return FALSE;

	if ( ES_MAGE(ch) )
		levmage = skill_table[sn].skill_level[CLASS_MAGE];
	if ( ES_CLERIC(ch) )
		levcleric = skill_table[sn].skill_level[CLASS_CLERIC];
	if ( ES_PSI(ch) )
		levpsi = skill_table[sn].skill_level[CLASS_PSI];
	if ( ES_WARRIOR(ch) )
		levwar = skill_table[sn].skill_level[CLASS_WARRIOR];
	if ( ES_THIEF(ch) )
		levth = skill_table[sn].skill_level[CLASS_THIEF];

	levarr[0]	= levmage;
	levarr[1]	= levcleric;
	levarr[2]	= levpsi;
	levarr[3]	= levwar;
	levarr[4]	= levth;

	cual		= getmin( levarr, 5 );

	switch(cual)
	{
		default:
		bugf("Can_cast_spell : cual == -1, vnum %d", CHARVNUM(ch) );
		return FALSE;

		case 0: clase = CLASS_MAGE;	break;
		case 1: clase = CLASS_CLERIC;	break;
		case 2: clase = CLASS_PSI;	break;
		case 3: clase = CLASS_WARRIOR;	break;
		case 4: clase = CLASS_THIEF;	break;
	}

	level = levarr[cual];

	if ( getNivelPr(ch) < level )
		return FALSE;

	if ( clase != CLASS_PSI && !CAN_SAY(ch) )
		return FALSE;

	if ( !can_cast( ch, sn, clase ) )
		return FALSE;

	return TRUE;
}

bool selfspell( CHAR_DATA *ch )
{
	int spell = 0;
	OBJ_DATA *obj = NULL;

	if ( (IS_AFFECTED(ch, AFF_POISON)
	   || IS_AFFECTED(ch, AFF_CURSE))
	&&   ES_PSI(ch)
	&&   can_cast_spell(ch, gsn_cell_adjustment) )
		spell = gsn_cell_adjustment;
	else
	if ( IS_AFFECTED(ch, AFF_FAERIE_FIRE)
	&&   can_cast_spell(ch, gsn_cancellation) )
		spell = gsn_cancellation;
	else
	if ( IS_AFFECTED(ch, AFF_PLAGUE)
	&&   can_cast_spell(ch, gsn_cure_disease) )
		spell = gsn_cure_disease;
	else
	if ( IS_AFFECTED(ch,AFF_POISON)
	&&   can_cast_spell(ch, gsn_cure_poison) )
		spell = gsn_cure_poison;
	else
	if ( IS_AFFECTED(ch,AFF_BLIND)
	&&  !is_affected(ch, gsn_fire_breath)
	&&  !is_affected(ch, gsn_dirt)
	&&   can_cast_spell(ch, gsn_cure_blindness) )
		spell = gsn_cure_blindness;
	else
	if ( IS_AFFECTED(ch, AFF_SLOW)
	&&   is_affected(ch, gsn_slow)
	&&   can_cast_spell(ch, gsn_cancellation) )
		spell = gsn_cancellation;
	else
	if ( ES_PSI(ch)
	&&  !IS_AFFECTED(ch, AFF_SANCTUARY)
	&&   can_cast_spell(ch, gsn_biofeedback) )
		spell = gsn_biofeedback;
	else
	if ( can_cast_spell(ch, gsn_sanctuary) )
		spell = gsn_sanctuary;
	else
	if ( ch->hit + 100 < ch->max_hit
	&&   can_cast_spell(ch, gsn_heal) )
		spell = gsn_heal;
	else
	if ( ch->mana > ch->max_mana / 2 )
	{
		obj = NULL;
		switch(number_range(1,24))
		{
			case 1:		spell = gsn_armor;		break;
			case 2:		spell = gsn_bless;		break;
			case 3:		spell = gsn_shield;		break;
			case 4:		if ( !IS_SET(ch->off_flags, OFF_FAST) )
						spell = gsn_haste;
					break;
			case 5:		if ( !is_affected( ch, gsn_enhanced_strength ) )
						spell = gsn_giant_strength;
					break;
			case 6:		if ( !IS_AFFECTED(ch, AFF_DETECT_HIDDEN) )
						spell = gsn_detect_hidden;
					break;
			case 7:		if ( (obj = get_eq_char(ch, WEAR_WIELD)) != NULL
					&&    obj->item_type == ITEM_WEAPON
					&&   !IS_WEAPON_STAT(obj, WEAPON_POISON)
					&&   !IS_WEAPON_STAT(obj, WEAPON_FLAMING)
					&&   !IS_WEAPON_STAT(obj, WEAPON_FROST)
					&&   !IS_WEAPON_STAT(obj, WEAPON_VAMPIRIC)
					&&   !IS_WEAPON_STAT(obj, WEAPON_SHARP)
					&&   !IS_WEAPON_STAT(obj, WEAPON_VORPAL)
					&&   !IS_WEAPON_STAT(obj, WEAPON_SHOCKING)
					&&   !IS_OBJ_STAT(obj, ITEM_BLESS)
					&&   !IS_OBJ_STAT(obj, ITEM_BURN_PROOF) )
						spell = gsn_poison;
					break;
			case 8:		if ( !is_affected( ch, gsn_flesh_armor ) )
						spell = gsn_stone_skin;
					break;
			case 9:		if ( !IS_AFFECTED2(ch, AFF_FLAMING_SHIELD) )
						spell = gsn_flaming_shield;
					break;
			case 10:	spell = gsn_concentracion;	break;
			case 11:	spell = gsn_enhance_health;	break;
			case 12 :	spell = gsn_adrenaline_control;	break;
			case 13 : 	if ( (obj = get_eq_char(ch, WEAR_WIELD)) != NULL
					&&   !IS_OBJ_STAT(obj, ITEM_BLESS) )
						spell = gsn_bless;
					break;
			case 14 : 	if ( !is_affected(ch, gsn_fireproof) && !ES_IMMUNE(ch, IMM_FIRE) )
						spell = gsn_fireproof;
					break;
			case 15 :	spell = gsn_displacement;		break;
			case 16 :	spell = gsn_energy_containment;		break;
			case 17 :	if ( !is_affected( ch, gsn_giant_strength ) )
						spell = gsn_enhanced_strength;
					break;
			case 18 :	if ( !is_affected( ch, gsn_stone_skin ) )
						spell = gsn_flesh_armor;
					break;
			case 19 :	spell = gsn_mental_barrier;	break;
			case 20 :	spell = gsn_thought_shield;	break;
			case 21 :	spell = gsn_concentracion;	break;
			case 22 :	spell = gsn_combat_mind;	break;
			case 23 :	if ( !IS_AFFECTED(ch, AFF_PROTECT_EVIL)
					&&   !IS_AFFECTED(ch, AFF_PROTECT_GOOD) )
						spell = gsn_inertial_barrier;
					break;
			case 24 :	spell = gsn_intellect_fortress;	break;
			case 25 :	if ( IS_EVIL(ch) )
						spell = gsn_protect_good;
					else
						spell = gsn_protect_evil;
					break;
		}
	}

	if ( spell > 0 && can_cast_spell(ch, spell) )
	{
		char buf[MIL];

		if ( obj && can_see_obj(ch, obj) )
		{
			unequip_char(ch, obj);
			sprintf( buf, "'%s' %s", skill_table[spell].name, obj->name );
			do_cast(ch, buf);
			equip_char(ch, obj, WEAR_WIELD);
		}
		else
		{
			sprintf( buf, "'%s'", skill_table[spell].name );
			do_cast( ch, buf );
		}

		return TRUE;
	}

	return FALSE;
}

void mob_cast( EVENT *ev )
{
	CHAR_DATA *ch = ev->item.ch;

	if ( !ch->fighting )
	{
		if ( ch->position != POS_STANDING )
			do_wake(ch, "");
		else
			selfspell(ch);
	}

	if ( ch->mana > ch->max_mana / 4
	&&   ch->in_room->area->nplayer > 0 )
		char_event_add( ch, UMAX(ch->wait, 2*PULSE_PER_SECOND), 0, mob_cast );
}

void try_to_steal( CHAR_DATA *ch )
{
	CHAR_DATA *pc;
	char buf[MIL];

	for ( pc = ch->in_room->people; pc; pc = pc->next_in_room )
		if (  ch != pc
		&&   !IS_NPC(pc)
		&&   !IS_IMMORTAL(pc)
		&&   !IS_BUILDER(pc, pc->in_room->area)
		&&   !is_friend( ch, pc )
		&&    CHANCE(getNivelPr(ch) + (getNivelPr(pc) - getNivelPr(ch))*10)
		&&    can_see( ch, pc )
		&&   !is_safe( ch, pc )
		&&    pc->position != POS_FIGHTING
		&&    ENTRE_I(getNivelPr(pc)-7,getNivelPr(ch),getNivelPr(pc)+7)
		&&  (!is_clan(ch) || (is_clan(pc) && !is_same_clan(ch, pc))) )
		{
			if (CHANCE(50))
				sprintf( buf, "coins %s", pc->name );
			else
			{
				OBJ_DATA * obj;

				for ( obj = pc->carrying; obj; obj = obj->next_content )
					if ( obj->wear_loc == WEAR_NONE
					&&   can_drop_obj( pc, obj )
					&&  !IS_SET( obj->extra_flags, ITEM_INVENTORY )
					&&   obj->level <= getNivelPr(ch) )
					sprintf( buf, "'%s' %s", obj->name, pc->name );
			}
			do_steal( ch, buf );
			return;
		}
}

void smart_event( EVENT *ev )
{
	CHAR_DATA *ch = ev->item.ch;

	if ( is_hunting(ch) )
		return;

	if ( ch->in_room->area->nplayer > 0 )
	{
		if ( ch->pIndexData->default_pos != POS_SLEEPING
		&&   ch->position == POS_SLEEPING
		&& ((IS_MOB_CASTER(ch) && !IS_AFFECTED(ch, AFF_SANCTUARY))
		||   pc_in_room(ch->in_room, ch) ) )
			do_wake( ch, "" );

		if ( ES_THIEF(ch)
		&&   CHANCE(getNivelPr(ch)) )
		{
			try_to_steal( ch );

			if (char_died(ch))
				return;
		}
	}

	if ( ch->position == POS_STANDING )
	{
		if ( IS_AFFECTED2(ch, AFF_HOLD)
		&&  !is_affected(ch, gsn_web) )
			do_untangle(ch, "");

		if ( ( (ch->hit < ch->max_hit * 0.5)
		  ||   (IS_MOB_CASTER(ch) && ch->mana < ch->max_mana*0.75) )
		&& (!IS_MOB_CASTER(ch) || IS_AFFECTED(ch, AFF_SANCTUARY))
		&&   ch->in_room->area->nplayer == 0 )
			do_sleep(ch, "");
	}

	char_event_add( ch, 2*PULSE_PER_SECOND, 0, smart_event );
}

int spell_dam_mage( CHAR_DATA *ch, CHAR_DATA *victim )
{
	if ( ch->race == RACE_VAMPIRE
	&&   getNivelPr(ch) > 40
	&&  !ES_IMMUNE(victim, DAM_POISON)
	&&   can_cast( ch, gsn_vampiric_bite, CLASS_MAGE )
	&&   CHANCE(50) )
		return gsn_vampiric_bite;
	else
	if ( getNivelPr(ch) > 26
	&&  !IS_PET(ch)
	&&   IS_NPC(victim)
	&&  !ES_IMMUNE(victim, IMM_HOLY)
	&&   can_cast( ch, gsn_power_word_of_kill, CLASS_MAGE ) )
		return gsn_power_word_of_kill;
	else
	if ( getNivelPr(ch) > 39
	&&  !ES_IMMUNE(victim, IMM_FIRE)
	&&  !ES_RES(victim, RES_FIRE)
	&&   can_cast( ch, gsn_fire_breath, CLASS_MAGE )
	&&   ch->mana > ch->max_mana * 2 / 3
	&&   CHANCE(80) )
		return gsn_fire_breath;
	else
	if ( getNivelPr(ch) > 33
	&&  !ES_IMMUNE(victim, IMM_COLD)
	&&  !ES_RES(victim, RES_COLD)
	&&   can_cast( ch, gsn_frost_breath, CLASS_MAGE )
	&&   ch->mana > ch->max_mana * 2 / 3
	&&   CHANCE(70) )
		return gsn_frost_breath;
	else
	if ( getNivelPr(ch) > 30
	&&  !ES_IMMUNE(victim, IMM_ACID)
	&&  !ES_RES(victim, RES_ACID)
	&&   can_cast( ch, gsn_acid_breath, CLASS_MAGE )
	&&   ch->mana > ch->max_mana * 2 / 3
	&&   CHANCE(60) )
		return gsn_acid_breath;
	else
	if ( getNivelPr(ch) > 27
	&&  !ES_IMMUNE(victim, IMM_ACID)
	&&   can_cast( ch, gsn_acid_blast, CLASS_MAGE )
	&&   CHANCE(80) )
		return gsn_acid_blast;
	else
	if ( getNivelPr(ch) > 30
	&&   can_cast( ch, gsn_hellspawn, CLASS_MAGE )
	&&   CHANCE(80) )
		return gsn_hellspawn;
	else
	if ( getNivelPr(ch) > 21
	&&  !ES_IMMUNE(victim, IMM_FIRE)
	&&   can_cast( ch, gsn_fireball, CLASS_MAGE )
	&&   CHANCE(70) )
		return gsn_fireball;
	else
	if ( getNivelPr(ch) > 18
	&&   can_cast( ch, gsn_energy_drain, CLASS_MAGE )
	&&   CHANCE(60) )
		return gsn_energy_drain;
	else
	if ( getNivelPr(ch) > 15
	&&   can_cast( ch, gsn_colour_spray, CLASS_MAGE )
	&&   CHANCE(60) )
		return gsn_colour_spray;
	else
	if ( getNivelPr(ch) > 9
	&&   can_cast( ch, gsn_shocking_grasp, CLASS_MAGE )
	&&   CHANCE(60) )
		return gsn_shocking_grasp;
	else
	if ( getNivelPr(ch) > 6
	&&   can_cast( ch, gsn_burning_hands, CLASS_MAGE )
	&&   CHANCE(60) )
		return gsn_burning_hands;
	else
	if ( getNivelPr(ch) > 3
	&&   can_cast( ch, gsn_chill_touch, CLASS_MAGE )
	&&   CHANCE(60) )
		return gsn_chill_touch;
	else
	if ( can_cast( ch, gsn_magic_missile, CLASS_MAGE )
	&&   (getNivelPr(ch) < 10 || ch->mana < ch->max_mana / 10) )
		return gsn_magic_missile;

	return -1;
}

int spell_aff_mage( CHAR_DATA *ch, CHAR_DATA *victim )
{
	if ( getNivelPr(ch) > 27
	&&  !IS_AFFECTED2(victim, AFF_MUTE)
	&&   can_cast( ch, gsn_mute, CLASS_MAGE )
	&&  (es_caster(victim) || CHANCE(20))
	&&  !saves_spell(getNivelPr(ch), victim, DAM_OTHER) )
		return gsn_mute;
	else
	if ( getNivelPr(ch) > 15
	&&  can_cast( ch, gsn_dispel_magic, CLASS_MAGE )
	&&  (IS_AFFECTED(victim, AFF_SANCTUARY)
	 ||  IS_AFFECTED(victim, AFF_HASTE)
	 || (IS_AFFECTED(victim, AFF_PROTECT_EVIL) && IS_EVIL(ch))
	 || (IS_AFFECTED(victim, AFF_PROTECT_GOOD) && IS_GOOD(ch)))
	&& !saves_spell(getNivelPr(ch), victim, DAM_OTHER) )
		return gsn_dispel_magic;
	else
	if ( getNivelPr(ch) > 23
	&& !IS_AFFECTED(victim, AFF_SLOW)
	&&  can_cast( ch, gsn_slow, CLASS_MAGE )
	&& !saves_spell(getNivelPr(ch), victim, DAM_OTHER) )
		return gsn_slow;
	else
	if ( getNivelPr(ch) > 11
	&&  !IS_AFFECTED(victim, AFF_BLIND)
	&&   can_cast( ch, gsn_blindness, CLASS_MAGE )
	&&  !saves_spell(getNivelPr(ch), victim, DAM_LIGHT) )
		return gsn_blindness;
	else
	if ( getNivelPr(ch) > 10
	&&  !IS_AFFECTED(victim, AFF_WEAKEN)
	&&   can_cast( ch, gsn_weaken, CLASS_MAGE )
	&&  !saves_spell(getNivelPr(ch), victim, DAM_OTHER) )
		return gsn_weaken;
	else
	if ( getNivelPr(ch) > 17
	&&  !IS_AFFECTED(victim, AFF_CURSE)
	&&   can_cast( ch, gsn_curse, CLASS_MAGE )
	&&  !saves_spell(getNivelPr(ch), victim, DAM_NEGATIVE) )
		return gsn_curse;
	else
	if ( !IS_AFFECTED2(victim, AFF_HOLD)
	&&    can_cast( ch, gsn_web, CLASS_MAGE )
	&&   !saves_spell(getNivelPr(ch), victim, DAM_OTHER) )
		return gsn_web;
	else
	if ( can_cast( ch, gsn_magic_missile, CLASS_MAGE )
	&&  (getNivelPr(ch) < 10 || ch->mana < ch->max_mana / 10) )
		return gsn_magic_missile;
	else
		return -1;
}