dawn/notes/
dawn/src/
dawn/src/docs/
/**************************************************************************/
// special.cpp - mob special functions
/***************************************************************************
 * The Dawn of Time v1.69r (c)1997-2004 Michael Garratt                    *
 * >> A number of people have contributed to the Dawn codebase, with the   *
 *    majority of code written by Michael Garratt - www.dawnoftime.org     *
 * >> To use this source code, you must fully comply with all the licenses *
 *    in licenses.txt... In particular, you may not remove this copyright  *
 *    notice.                                                              *
 ***************************************************************************
 * >> Original Diku Mud copyright (c)1990, 1991 by Sebastian Hammer,       *
 *    Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, & Katja Nyboe.   *
 * >> Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael       *
 *    Chastain, Michael Quan, and Mitchell Tse.                            *
 * >> ROM 2.4 is copyright 1993-1995 Russ Taylor and has been brought to   *
 *    you by the ROM consortium: Russ Taylor(rtaylor@pacinfo.com),         *
 *    Gabrielle Taylor(gtaylor@pacinfo.com) & Brian Moore(rom@rom.efn.org) *
 * >> Oblivion 1.2 is copyright 1996 Wes Wagner                            *
 **************************************************************************/
#include "include.h" // dawn standard includes
#include "magic.h"

void do_unlock( char_data *ch, char *argument );
void do_lock(   char_data *ch, char *argument );
void do_order(  char_data *ch, char *argument );
void do_pkill( char_data *ch, char *argument );

void say_spell( char_data *ch, int sn, CLASS_CAST_TYPE type );

// these really only relate to rom based area files
#define MOB_VNUM_PATROLMAN         2106 
#define GROUP_VNUM_TROLLS          2100
#define GROUP_VNUM_OGRES           2101

/* direction command procedures needed */
DECLARE_DO_FUN(do_north     );
DECLARE_DO_FUN(do_south     );
DECLARE_DO_FUN(do_west      );
DECLARE_DO_FUN(do_east      );

/* other command procedures needed */
DECLARE_DO_FUN(do_pbackstab  );
DECLARE_DO_FUN(do_close     );
DECLARE_DO_FUN(do_flee      );
DECLARE_DO_FUN(do_kill      );
DECLARE_DO_FUN(do_open      );
DECLARE_DO_FUN(do_say       );
DECLARE_DO_FUN(do_sleep     );
DECLARE_DO_FUN(do_wake      );
DECLARE_DO_FUN(do_yell      );


// The following special functions are available for MOBS
DECLARE_SPEC_FUN(	spec_breath_any			);
DECLARE_SPEC_FUN(	spec_breath_acid		);
DECLARE_SPEC_FUN(	spec_breath_fire		);
DECLARE_SPEC_FUN(	spec_breath_frost		);
DECLARE_SPEC_FUN(	spec_breath_gas			);
DECLARE_SPEC_FUN(	spec_breath_lightning	);
DECLARE_SPEC_FUN(	spec_breath_steam		);
DECLARE_SPEC_FUN(	spec_cast_adept			);
DECLARE_SPEC_FUN(	spec_cast_cleric		);
DECLARE_SPEC_FUN(	spec_cast_druid			);
DECLARE_SPEC_FUN(	spec_cast_mage			);
DECLARE_SPEC_FUN(	spec_cast_undead		);
DECLARE_SPEC_FUN(	spec_fido				);
DECLARE_SPEC_FUN(	spec_guard				);
DECLARE_SPEC_FUN(	spec_janitor			);
DECLARE_SPEC_FUN(	spec_mayor				);
DECLARE_SPEC_FUN(	spec_poison				);
DECLARE_SPEC_FUN(	spec_thief				);
DECLARE_SPEC_FUN(	spec_nasty				);
DECLARE_SPEC_FUN(	spec_gold_dragon        );
DECLARE_SPEC_FUN(	spec_red_drac           );
DECLARE_SPEC_FUN(	spec_fearful            );
DECLARE_SPEC_FUN(	spec_lava_monster       ); 	
DECLARE_SPEC_FUN(	spec_assassin       	); 
DECLARE_SPEC_FUN(	spec_beggar				); 
DECLARE_SPEC_FUN(	spec_summoned_guardian	); 
DECLARE_SPEC_FUN(	spec_elf_muncher		); 
DECLARE_SPEC_FUN(	spec_shadow_dragon		);
DECLARE_SPEC_FUN(	spec_steel_dragon		);
DECLARE_SPEC_FUN(	spec_cast_mean			);
DECLARE_SPEC_FUN(	spec_cast_meaner		);
DECLARE_SPEC_FUN(	spec_charmer			);
DECLARE_SPEC_FUN(   spec_master_thief       );
DECLARE_SPEC_FUN(	spec_questmaster		);
DECLARE_SPEC_FUN(	spec_troll_member		);
DECLARE_SPEC_FUN(	spec_ogre_member		);
DECLARE_SPEC_FUN(	spec_clan_transport     );

// The following special functions are available for OBJS
DECLARE_OSPEC_FUN(	spec_obj_test			);

// Special Functions Table -- MOBS
const	struct	spec_type	spec_table	[ ] =
{
    // Special function commands.

    { "spec_breath_any",		spec_breath_any			},
    { "spec_breath_acid",		spec_breath_acid		},
    { "spec_breath_fire",		spec_breath_fire		},
    { "spec_breath_frost",		spec_breath_frost		},
    { "spec_breath_gas",		spec_breath_gas			},
    { "spec_breath_lightning",	spec_breath_lightning	},
    { "spec_breath_steam",		spec_breath_steam		},	
    { "spec_cast_adept",		spec_cast_adept			},
    { "spec_cast_cleric",		spec_cast_cleric		},
    { "spec_cast_druid",		spec_cast_druid			},
    { "spec_cast_mage",			spec_cast_mage			},
    { "spec_cast_undead",		spec_cast_undead		},
    { "spec_fido",				spec_fido				},
    { "spec_guard",				spec_guard				},
    { "spec_janitor",			spec_janitor			},
    { "spec_mayor",				spec_mayor			    },
    { "spec_poison",			spec_poison				},
    { "spec_thief",				spec_thief			    },
    { "spec_nasty",				spec_nasty				},
    { "spec_gold_dragon",		spec_gold_dragon		},
    { "spec_red_drac",			spec_red_drac			}, 
    { "spec_fearful",			spec_fearful			},
    { "spec_lava_monster",		spec_lava_monster		},  
    { "spec_assassin",			spec_assassin			},      
    { "spec_beggar",			spec_beggar				},
    { "spec_summoned_guardian", spec_summoned_guardian	},      
    { "spec_elf_muncher",		spec_elf_muncher		},      
    { "spec_shadow_dragon",		spec_shadow_dragon		},      
    { "spec_steel_dragon",		spec_steel_dragon		},
    { "spec_charmer",           spec_charmer            },
    { "spec_master_thief",      spec_master_thief       },
    { "spec_cast_mean",			spec_cast_mean			},
    { "spec_cast_meaner",		spec_cast_meaner		},
    { "spec_questmaster",		spec_questmaster		},
    { "spec_troll_member",		spec_troll_member		},
    { "spec_ogre_member",		spec_ogre_member		},
    { "spec_clan_transport",	spec_clan_transport		},	
	{ "",						0						}
};

// Special Functions Table -- OBJS
const   struct  ospec_type    ospec_table[] =
{
    { "spec_obj_test",			spec_obj_test			},
	{	NULL,					NULL					}
};

/*****************************************************************************
 Name:		ospec_lookup
 Purpose:	Given a name, return the appropriate object spec fun.
 ****************************************************************************/
OSPEC_FUN *ospec_lookup( const char *name )
{
	int i;
	for ( i = 0; ospec_table[i].ospec_name != NULL; i++)
	{
		if (LOWER(name[0]) == LOWER(ospec_table[i].ospec_name[0])
			&&  !str_prefix( name,ospec_table[i].ospec_name))
			return ospec_table[i].ospec_fun;
	}
	return 0;
}


/*****************************************************************************
 Name:		spec_lookup
 Purpose:	Given a name, return the appropriate mobile spec fun.
 Called by:	do_mset(act_wiz.c) load_specials,reset_area(db.c)
 ****************************************************************************/
SPEC_FUN *spec_lookup( const char *name )	// OLC
{
	int cmd;
	char buf[MSL], bufmatch[MSL];
	
	sprintf(buf, name);
	
	buf[5]='\0';
	if (!str_cmp( buf, "spec_"))
	{
		sprintf(bufmatch, name);
	}
	else
	{
		sprintf(bufmatch,"spec_%s", name);
	}
	
	for ( cmd = 0; !IS_NULLSTR(spec_table[cmd].spec_name); cmd++ )
		if ( !str_prefix( bufmatch, spec_table[cmd].spec_name ) )
			return spec_table[cmd].spec_fun;
		
	return NULL;
}

/*****************************************************************************
 Name:		spec_string
 Purpose:	Given a function, return the appropriate name.
 Called by:	<???>
 ****************************************************************************/
char *spec_string( SPEC_FUN *fun )	/* OLC */
{
	int cmd;
	
	for ( cmd = 0; spec_table[cmd].spec_fun; cmd++ )
		if ( fun == spec_table[cmd].spec_fun )
			return spec_table[cmd].spec_name;
		
		return 0;
}

/***************************************************************************/
/*modified for OLC */
char *spec_name( SPEC_FUN *function)
{
	char *i;
	i=spec_string( function );
	return i;
}

/***************************************************************************/
// returns the name of the object special function
char *ospec_name( OSPEC_FUN *function)
{
	int i;

	for (i = 0; ospec_table[i].ospec_fun != NULL; i++)
	{
		if (function == ospec_table[i].ospec_fun )
			return ospec_table[i].ospec_name;
	}
	return NULL;
}

/***************************************************************************
 !!!!!!!!!!!!!!!!!!!!!!!MOB SPECIAL FUNCTIONS BELOW HERE!!!!!!!!!!!!!!!!!!!!
 ***************************************************************************/
bool spec_fearful( char_data *ch )
{
	if(ch->position==POS_FIGHTING)
	{
		do_yell(ch,"HELP! I am being attacked!!! HELP!!!");
		do_flee(ch,"");
		return true;
	}
	return false ;
}

/***************************************************************************/ 
bool spec_red_drac( char_data *ch )
{
    char_data *victim;
    char_data *v_next;
    char *spell;
    int sn;
	
    if(ch->position!=POS_FIGHTING)
    {
		if(ch->hit<ch->max_hit)
		{
			sn = gsn_heal;
			(*skill_table[sn].spell_fun) (sn, ch->level, ch, ch, TARGET_CHAR);
		}
		if(number_range(1,100)>99)
		{
			switch(number_range(0,3))
			{
			case 0: spell = "haste"; break;
			case 1: spell = "fire shield"; break;
			case 2: spell = "protection good"; break;
			case 3: spell = "sanctuary"; break; 
			default: spell = "protection good"; break;
			}
			if( ( sn = skill_lookup(spell) ) < 0 ) return false;
			(*skill_table[sn].spell_fun) ( sn, ch->level, ch, ch,TARGET_CHAR);
			return true;
			
		}	  
		return false;
    }
	
    for ( victim = ch->in_room->people; victim != NULL; victim = v_next )
    {
        v_next = victim->next_in_room;
        if ( victim->fighting == ch ) 
            break;
    }
    
    if ( victim == NULL )
        return false;
	
    for ( ; ; )
    {
        switch ( number_bits( 4 ) )
        {
        case  0: spell = "blindness";			break;
        case  1: spell = "chain lightning";		break;
        case  2: spell = "acid blast";			break;
        case  3: spell = "chain lightning";		break;
        case  4: spell = "frostball";			break;
        case  5: spell = "curse";				break;
        case  6: spell = "poison";				break;
        case  7: spell = "heat metal";			break;
        case  8: spell = "teleport";			break;
        case  9:
        case 10: spell = "wrath";				break;
        case 11: spell = "prismatic spray";		break;
        default: spell = "dispel magic";		break;
        }
		break ;
    }
    if ( ( sn = skill_lookup( spell ) ) < 0 )
        return false;
    (*skill_table[sn].spell_fun) ( sn, ch->level, ch, victim,TARGET_CHAR);
    return true;
}

/***************************************************************************/	
bool spec_nasty( char_data *ch )
{
    char_data *victim, *v_next;
	long gold;
	
    if (!IS_AWAKE(ch)) {
		return false;
    }

    if (ch->position != POS_FIGHTING ) {
		for ( victim = ch->in_room->people; victim != NULL; victim = v_next)
		{
			v_next = victim->next_in_room;
			if (!IS_NPC(victim)
				&& (victim->level > ch->level)
				&& (victim->level < ch->level + 10))
			{
				do_pbackstab(ch,victim->name);
				if (ch->position != POS_FIGHTING){
					do_pkill(ch,victim->name);
				}
				// should steal some coins right away? :) 
				return true;
			}
		}
		return false;    //  No one to attack 
    }
	
	// okay, we must be fighting.... steal some coins and flee 
    if ( (victim = ch->fighting) == NULL)
        return false;   /* let's be paranoid.... */
	
    switch ( number_bits(2) )
    {
	case 0:  act( "$n rips apart your coin purse, spilling your gold!",
				 ch, NULL, victim, TO_VICT);
		act( "You slash apart $N's coin purse and gather his gold.",
			ch, NULL, victim, TO_CHAR);
		act( "$N's coin purse is ripped apart!",
			ch, NULL, victim, TO_NOTVICT);
		gold = victim->gold / 10;  /* steal 10% of his gold */
		victim->gold -= gold;
		ch->gold     += gold;
		return true;
		
		  case 1:  do_flee( ch, "");
			  return true;
			  
		  default: return false;
    }
}

// Core procedure for dragons.

/***************************************************************************/
bool dragon( char_data *ch, char *spell_name )
{
    char_data *victim;
    char_data *v_next;
    int sn;
	
    if ( ch->position != POS_FIGHTING )
		return false;
	
    for ( victim = ch->in_room->people; victim != NULL; victim = v_next )
    {
		v_next = victim->next_in_room;
		if ( victim->fighting == ch && number_bits( 3 ) == 0 )
			break;
	}
	
    if ( victim == NULL )
		return false;
	
    if ( ( sn = skill_lookup( spell_name ) ) < 0 )
		return false;
	(*skill_table[sn].spell_fun) ( sn, ch->level, ch, victim, TARGET_CHAR);
    return true;
}




// Special procedures for mobiles.

/***************************************************************************/
bool spec_breath_any( char_data *ch )
{
	if ( ch->position != POS_FIGHTING )
		return false;

	switch ( number_bits( 3 ) )
	{
		case 0: return spec_breath_fire		( ch );
		case 1:
		case 2: return spec_breath_lightning( ch );
		case 3: return spec_breath_gas		( ch );
		case 4: return spec_breath_acid		( ch );
		case 5:
		case 6:
		case 7: return spec_breath_frost	( ch );
    }

    return false;
}

/***************************************************************************/
bool spec_breath_acid( char_data *ch )
{
    return dragon( ch, "acid breath" );
}

/***************************************************************************/
bool spec_breath_fire( char_data *ch )
{
    return dragon( ch, "fire breath" );
}

/***************************************************************************/
bool spec_breath_frost( char_data *ch )
{
    return dragon( ch, "frost breath" );
}
/***************************************************************************/
bool spec_breath_steam( char_data* ch )
{
    if ( ch->wait > 0 )
        return false;

    if ( is_affected(ch, gsn_neck_thrust))
		return false;
    return dragon( ch, "steam breath" );
}

/***************************************************************************/
bool spec_breath_gas( char_data *ch )
{
    int sn;
	
    if ( ch->position != POS_FIGHTING )
		return false;
	
    if (( sn = gsn_gas_breath) < 0 )
		return false;
    (*skill_table[sn].spell_fun) ( sn, ch->level, ch, NULL,TARGET_CHAR);
    return true;
}

/***************************************************************************/
bool spec_gold_dragon( char_data *ch )
{
	
	if(ch->in_room==NULL)
		return false;
	
	if( (ch->in_room->vnum==15024) && (ch->in_room->exit[3]!=NULL) 
		&& (!IS_SET(ch->in_room->exit[3]->exit_info,EX_CLOSED)))
	{
		if(!IS_AWAKE(ch))
		{ do_wake(ch,""); }
		else
		{ do_west(ch,""); }
		return true;
	}
	
	if( (ch->in_room->vnum==15025) && (ch->position!=POS_FIGHTING) )
	{
		do_east(ch, "");
		do_sleep(ch, "");
		return true;
	}
	
	if(ch->position==POS_FIGHTING)
	{	
		switch ( number_bits( 2 ) )
		{
        case 0: return dragon(ch, "prismatic spray"); 
		case 1: return dragon(ch, "fire breath");
		case 2: return dragon(ch, "gas breath");
		case 3: return dragon(ch, "acid breath");
		} 	
		
	}	
	
	return false;	
}
/***************************************************************************/
bool spec_breath_lightning( char_data *ch )
{
    return dragon( ch, "lightning breath" );
}

/***************************************************************************/
// This is the 'healer' system
bool spec_cast_adept( char_data *ch )
{
    char_data *victim;
    char_data *v_next;
	int sn;

    if ( !IS_AWAKE(ch) )
	return false;

    for ( victim = ch->in_room->people; victim != NULL; victim = v_next )
    {
		v_next = victim->next_in_room;
		if ( victim != ch && can_see( ch, victim ) && number_bits( 1 ) == 0 
			&& !IS_NPC(victim) && victim->level < 21)
			break;
	}

	if ( victim == NULL )
		return false;

	switch ( number_range(0,12) )
	{
	case 0:
		sn=gsn_armor;
		if ( !is_affected( victim, sn ))
		{
			act( "$n utters the word 'abrazak'.", ch, NULL, NULL, TO_ROOM );
			spell_armor( sn, ch->level,ch,victim,TARGET_CHAR);
		}
		return true;

	case 1:
		sn=gsn_bless;
		if ( !is_affected( victim, sn ))
		{
			act( "$n utters the word 'fido'.", ch, NULL, NULL, TO_ROOM );
			spell_bless( sn, ch->level,ch,victim,TARGET_CHAR);
		}
		return true;

	case 2:
		sn=gsn_cure_blindness;
		if ( IS_AFFECTED(victim, AFF_BLIND))
		{
			act("$n utters the words 'judicandus noselacri'.",ch,NULL,NULL,TO_ROOM);
			spell_cure_blindness( sn, ch->level, ch, victim,TARGET_CHAR);
		}
		return true;

	case 3:
		sn=gsn_cure_light;
		if ( victim->hit != victim->max_hit )
		{
			act("$n utters the words 'judicandus dies'.", ch,NULL, NULL, TO_ROOM );
			spell_cure_light( sn, ch->level, ch, victim,TARGET_CHAR);
		}
		return true;

	case 4:
		sn=gsn_cure_poison;
		if ( is_affected( victim, gsn_poison ))
		{
			act( "$n utters the words 'judicandus sausabru'.",ch,NULL,NULL,TO_ROOM);
			spell_cure_poison( sn, ch->level, ch, victim,TARGET_CHAR);
		}
		return true;

	case 5:
		sn=gsn_refresh;
		if ((victim->max_move != victim->move))
		{
			act("$n utters the word 'candusima'.", ch, NULL, NULL, TO_ROOM );
			spell_refresh( sn,ch->level,ch,victim,TARGET_CHAR);
		}
		return true;

	case 6:
		sn=gsn_cure_disease;
		if ( is_affected( victim, gsn_plague ))
		{
			act("$n utters the words 'judicandus eugzagz'.",ch,NULL,NULL,TO_ROOM);
			spell_cure_disease( sn,	ch->level,ch,victim,TARGET_CHAR);
		}
		return true;
	}
    return false;
}

/***************************************************************************/
bool spec_cast_cleric( char_data *ch )
{
	char_data *victim;
	char_data *v_next;
	char *spell;
	int sn;

    if ( ch->position != POS_FIGHTING 
		|| ch->wait>0 
		|| IS_AFFECTED(ch,AFF2_MUTE)
		|| IS_AFFECTED( ch, AFF_BLIND ) // because they can't see the target, most are target spells
		|| IS_SET( ch->in_room->affected_by, ROOMAFF_CONE_OF_SILENCE ) ){
		return false;
	}
	
    for ( victim = ch->in_room->people; victim != NULL; victim = v_next )
	{
		v_next = victim->next_in_room;
		if ( victim->fighting == ch && number_bits( 2 ) == 0 )
			break;
    }

	if ( victim == NULL )
		return false;

    for ( ; ; )
    {
		int min_level;

		switch ( number_bits( 4 ) )
		{
			case  0: min_level =  0; spell = "blindness";      break;
			case  1: min_level =  3; spell = "cause serious";  break;
			case  2: min_level =  7; spell = "earthquake";     break;
			case  3: min_level =  9; spell = "cause critical"; break;
			case  4: min_level = 10; spell = "dispel evil";    break;
			case  5: min_level = 12; spell = "curse";          break;
			case  6: min_level = 12; spell = "change sex";     break;
			case  7: min_level = 13; spell = "flamestrike";    break;
			case  8: min_level = 14; spell = "cause headache"; break; //Y: mobs cause headache too!!
			case  9:
			case 10: min_level = 15; spell = "harm";           break;
			case 11: min_level = 15; spell = "plague";	   break;
			default: min_level = 16; spell = "dispel magic";   break;
		}

		if ( ch->level >= min_level )
		    break;
	}

	if ( ( sn = skill_lookup( spell ) ) < 0 )
		return false;

	say_spell(ch, sn, CCT_CLERIC);
    (*skill_table[sn].spell_fun) ( sn, ch->level, ch, victim,TARGET_CHAR);
	return true;
}

/***************************************************************************/
bool spec_cast_druid( char_data *ch )
{
	char_data *victim;
    char_data *v_next;
    char *spell;
	int sn;
	
    if ( ch->position != POS_FIGHTING 
		|| ch->wait>0 
		|| IS_AFFECTED(ch,AFF2_MUTE)
		|| IS_AFFECTED( ch, AFF_BLIND ) // because they can't see the target, most are target spells
		|| IS_SET( ch->in_room->affected_by, ROOMAFF_CONE_OF_SILENCE ) ){
		return false;
	}
	
    for ( victim = ch->in_room->people; victim != NULL; victim = v_next )
	{
		v_next = victim->next_in_room;
		if ( victim->fighting == ch && number_bits( 2 ) == 0 )
			break;
    }
	
    if ( victim == NULL )
		return false;
	
    for ( ; ; )
    {
		int min_level;
		
		switch ( number_bits( 4 ) )
		{
		case  0: min_level =  0; spell = "faerie fire";      break;
		case  1: min_level =  3; spell = "withering";        break;
		case  2: min_level =  6; spell = "vitality drain";   break;
		case  3: min_level =  9; spell = "closed eyes";      break;
		case  4: min_level = 12; spell = "snake bite";       break;
		case  5: min_level = 15; spell = "remove spells";    break;
		case  6: min_level = 18; spell = "merciless hunger"; break;
		case  7: min_level = 21; spell = "merciless thirst"; break;
		case  8: min_level = 20; spell = "black death";      break;
		case  9: min_level = 50; spell = "flamestorm";       break;
		default: min_level = 18; spell = "destroy living";   break;
		}
		
		if ( ch->level >= min_level )
			break;
    }
	
    if ( ( sn = skill_lookup( spell ) ) < 0 )
		return false;
	say_spell(ch, sn, CCT_DRUID);
    (*skill_table[sn].spell_fun) ( sn, ch->level, ch, victim,TARGET_CHAR);
    return true;
}

/***************************************************************************/
bool spec_cast_judge( char_data *ch )
{
	 char_data *victim;
    char_data *v_next;
    char *spell;
    int sn;
 
    if ( ch->position != POS_FIGHTING 
		|| ch->wait>0 
		|| IS_AFFECTED(ch,AFF2_MUTE)
		|| IS_AFFECTED( ch, AFF_BLIND ) // because they can't see the target, most are target spells
		|| IS_SET( ch->in_room->affected_by, ROOMAFF_CONE_OF_SILENCE ) ){
		return false;
	}
	
    for ( victim = ch->in_room->people; victim != NULL; victim = v_next )
    {
        v_next = victim->next_in_room;
        if ( victim->fighting == ch && number_bits( 2 ) == 0 )
            break;
    }
 
    if ( victim == NULL )
        return false;
 
    spell = "high explosive";
    if ( ( sn = skill_lookup( spell ) ) < 0 )
        return false;
    (*skill_table[sn].spell_fun) ( sn, ch->level, ch, victim,TARGET_CHAR);
    return true;
}

/***************************************************************************/
bool spec_cast_mage( char_data *ch )
{
    char_data *victim;
    char_data *v_next;
    char *spell;
    int sn;

    if ( ch->position != POS_FIGHTING 
		|| ch->wait>0 
		|| IS_AFFECTED(ch,AFF2_MUTE)
		|| IS_AFFECTED( ch, AFF_BLIND ) // because they can't see the target, most are target spells
		|| IS_SET( ch->in_room->affected_by, ROOMAFF_CONE_OF_SILENCE ) ){
		return false;
	}

    for ( victim = ch->in_room->people; victim != NULL; victim = v_next )
    {
	v_next = victim->next_in_room;
	if ( victim->fighting == ch && number_bits( 2 ) == 0 )
	    break;
    }

    if ( victim == NULL )
	return false;

    for ( ;; )
	{
	int min_level;

	switch ( number_bits( 4 ) )
	{
	    case  0: min_level =  0; spell = "burning hands";  break;
		case  1: min_level =  3; spell = "chill touch";    break;
		case  2: min_level =  7; spell = "weaken";         break;
		case  3: min_level =  8; spell = "teleport";       break;
		case  4: min_level = 11; spell = "colour spray";   break;
		case  5: min_level = 12; spell = "change sex";     break;
		case  6: min_level = 13; spell = "energy drain";   break;
		case  7: 
		case  8:
		case  9: min_level = 15; spell = "fireball";       break;
		case 10: min_level = 20; spell = "decay";          break;
		case 11: min_level = 30; spell = "cause fear";     break;
		case 12: min_level = 50; spell = "chaotic poison"; break;
		default: min_level = 20; spell = "acid blast";     break;
	}

	if ( ch->level >= min_level )
	    break;
    }

    if ( ( sn = skill_lookup( spell ) ) < 0 ){
		return false;
	}


	say_spell(ch, sn, CCT_MAGE);
    (*skill_table[sn].spell_fun) ( sn, ch->level, ch, victim,TARGET_CHAR);
    return true;
}

/***************************************************************************/
bool spec_cast_undead( char_data *ch )
{
    char_data *victim;
    char_data *v_next;
    char *spell;
    int sn;
	
    if ( ch->position != POS_FIGHTING 
		|| ch->wait>0 
		|| IS_AFFECTED(ch,AFF2_MUTE)
		|| IS_AFFECTED( ch, AFF_BLIND ) // because they can't see the target, most are target spells
		|| IS_SET( ch->in_room->affected_by, ROOMAFF_CONE_OF_SILENCE ) ){
		return false;
	}
	
    for ( victim = ch->in_room->people; victim != NULL; victim = v_next )
    {
		v_next = victim->next_in_room;
		if ( victim->fighting == ch && number_bits( 2 ) == 0 )
			break;
    }
	
	if ( victim == NULL )
		return false;
	
    for ( ;; )
    {
		int min_level;
		
		switch ( number_bits( 4 ) )
		{
		case  0: min_level =  0; spell = "curse";          break;
		case  1: min_level =  3; spell = "weaken";         break;
		case  2: min_level =  6; spell = "chill touch";    break;
		case  3: min_level =  9; spell = "blindness";      break;
		case  4: min_level = 12; spell = "poison";         break;
		case  5: min_level = 15; spell = "energy drain";   break;
		case  6: min_level = 18; spell = "harm";           break;
		case  7: min_level = 21; spell = "teleport";       break;
		case  8: min_level = 20; spell = "plague";	   break;
		default: min_level = 18; spell = "harm";           break;
		}
		
		if ( ch->level >= min_level )
			break;
    }
	
    if ( ( sn = skill_lookup( spell ) ) < 0 )
		return false;
    (*skill_table[sn].spell_fun) ( sn, ch->level, ch, victim,TARGET_CHAR);
    return true;
}

/***************************************************************************/
bool spec_fido( char_data *ch )
{
    OBJ_DATA *corpse;
	OBJ_DATA *c_next;
    OBJ_DATA *obj;
    OBJ_DATA *obj_next;
	
    if ( !IS_AWAKE(ch) )
		return false;
	
    for ( corpse = ch->in_room->contents; corpse != NULL; corpse = c_next )
    {
		c_next = corpse->next_content;
		if ( corpse->item_type != ITEM_CORPSE_NPC )
			continue;
		
		act( "$n savagely devours a corpse.", ch, NULL, NULL, TO_ROOM );
		for ( obj = corpse->contains; obj; obj = obj_next )
		{
			obj_next = obj->next_content;
			obj_from_obj( obj );
			obj_to_room( obj, ch->in_room );
		}
		extract_obj( corpse );
		return true;
    }
	
	return false;
}

/***************************************************************************/
bool spec_guard( char_data *)
{
    return false;
}

/***************************************************************************/
bool spec_janitor( char_data *ch )
{
    OBJ_DATA *trash;
    OBJ_DATA *trash_next;
	
    if ( !IS_AWAKE(ch) )
		return false;
	
    for ( trash = ch->in_room->contents; trash != NULL; trash = trash_next )
    {
        trash_next = trash->next_content;
        if ( !IS_SET( trash->wear_flags, OBJWEAR_TAKE )
            || (trash->item_type == ITEM_CORPSE_PC)
            || !can_loot(ch,trash))
            continue;
		
        if ( trash->item_type == ITEM_DRINK_CON
			||   trash->item_type == ITEM_TRASH
			||   trash->cost < 10 )
        {
            act( "$n picks up some trash.", ch, NULL, NULL, TO_ROOM );
            obj_from_room( trash );
            obj_to_char( trash, ch );
            return true;
        }
    }
	
    return false;
}

/***************************************************************************/
bool spec_mayor( char_data *ch )
{
	static const char open_path[] =
		"W3a3003b33000c111d0d111Oe333333Oe22c222112212111a1S.";
	
    static const char close_path[] =
		"W3a3003b33000c111d0d111CE333333CE22c222112212111a1S.";
	
    static const char *path;
    static int pos;
    static bool move;
	
    if ( !move )
    {
		if ( time_info.hour ==  6 )
		{
			path = open_path;
			move = true;
			pos  = 0;
		}
		
		if ( time_info.hour == 20 )
		{
			path = close_path;
			move = true;
			pos  = 0;
		}
    }
	
    if ( ch->fighting != NULL )
		return spec_cast_mage( ch );
    if ( !move || ch->position < POS_SLEEPING )
		return false;
	
    switch ( path[pos] )
    {
    case '0':
    case '1':
    case '2':
    case '3':
		move_char( ch, path[pos] - '0', false );
		break;
		
    case 'W':
		ch->position = POS_STANDING;
		act( "$n awakens and groans loudly.", ch, NULL, NULL, TO_ROOM );
		break;
		
    case 'S':
		ch->position = POS_SLEEPING;
		act( "$n lies down and falls asleep.", ch, NULL, NULL, TO_ROOM );
		break;
		
    case 'a':
		act( "$n says 'Hello Whore!'", ch, NULL, NULL, TO_ROOM );
		break;
		
    case 'b':
		act( "$n says 'These Humans can not clean up after themselves.'",
			ch, NULL, NULL, TO_ROOM );
		break;
		
    case 'c':
		act( "$n says 'Vandals!  I shall see them Hung!'",
			ch, NULL, NULL, TO_ROOM );
		break;
		
    case 'd':
		act( "$n says 'Out of my way!'", ch, NULL, NULL, TO_ROOM );
		break;
		
    case 'e':
		act( "$n says 'I hereby declare this wretched city open!'",
			ch, NULL, NULL, TO_ROOM );
		break;
		
    case 'E':
		act( "$n says 'I hereby declare this wretched city closed!'",
			ch, NULL, NULL, TO_ROOM );
		break;
		
    case 'O':
		do_unlock( ch, "gate" ); 
		do_open( ch, "gate" );
		break;
		
    case 'C':
		do_close( ch, "gate" );
		do_lock( ch, "gate" ); 
		break;
		
    case '.' :
		move = false;
		break;
    }
	
    pos++;
    return false;
}

/***************************************************************************/
bool spec_poison( char_data *ch )
{
    char_data *victim;
	
	victim = ch->fighting;
	
    if ( ch->position != POS_FIGHTING
		||   !victim
		||   number_percent( ) > 2 * ch->level )
		return false;
	
    act( "You bite $N!",  ch, NULL, victim, TO_CHAR    );
    act( "$n bites $N!",  ch, NULL, victim, TO_NOTVICT );
    act( "$n bites you!", ch, NULL, victim, TO_VICT    );
    spell_poison( gsn_poison, ch->level, ch, victim,TARGET_CHAR);
    return true;
}

/***************************************************************************/
bool spec_thief( char_data *ch )
{
    char_data *victim;
    char_data *v_next;
    long gold,silver;
	
    if ( ch->position != POS_STANDING )
		return false;
	
    for ( victim = ch->in_room->people; victim != NULL; victim = v_next )
    {
		v_next = victim->next_in_room;
		
		if ( IS_NPC(victim)
			||   victim->level >= LEVEL_IMMORTAL
			||   number_bits( 5 ) != 0 
			||   !can_see(ch,victim))
			continue;
		
		if ( IS_AWAKE(victim) && number_range( 0, ch->level ) == 0 )
		{
			act( "You discover $n's hands in your wallet!",
				ch, NULL, victim, TO_VICT );
			act( "$N discovers $n's hands in $S wallet!",
				ch, NULL, victim, TO_NOTVICT );
			return true;
		}
		else
		{
			gold = victim->gold * UMIN(number_range(1,20),ch->level / 2) / 100;
			gold = UMIN(gold, ch->level * ch->level * 10 );
			ch->gold     += gold;
			victim->gold -= gold;
			silver = victim->silver * UMIN(number_range(1,20),ch->level/2)/100;
			silver = UMIN(silver,ch->level*ch->level * 25);
			ch->silver	+= silver;
			victim->silver -= silver;
			return true;
		}
    }
	
    return false;
}

/*************************************************************************
 *                                                                       *
 *  Lava monster comes out of his lair after few ticks of someone        *
 *  being on his bridge - Kalahn & Raine - Apr 97                        *
 *                                                                       *
 ************************************************************************/
bool spec_lava_monster( char_data *ch )
{
	static ROOM_INDEX_DATA *bridge[5];
	static long last_tick = 0;
	static int wake_countdown = 3 , /* countdown before mob awakens */
		mob_state = 0; /* state mob is in - 0 = sleeping in lair */
	int room_index;
	bool player_found;
	
	if(ch->in_room==NULL)
		return false;
	
	if (!bridge[0] ) /* load pointers to all the rooms required */
	{      
        bridge[0] = get_room_index(29646); /* lava monsters lair         */
        bridge[1] = get_room_index(29627); /* just outside his lair      */
        bridge[2] = get_room_index(29626); /* on northern end of bridge  */
        bridge[3] = get_room_index(29625); /* on southern end of bridge  */
        bridge[4] = get_room_index(29624); /* just south of bridge       */
	}

	for(int checkrooms=0; checkrooms<5; checkrooms++){
		if(!bridge[checkrooms]){
			return false;
		}
	}
	
	/* Every tick check for people around or on the lava bridge
	- this is used to delay the lava monster from coming out straight away
    */
	if (tick_counter > last_tick)
		
	{ /* a tick has past */
        last_tick = tick_counter;
		
        /* check all along bridge for a players */
        player_found = false;
        for (room_index=1; room_index<=4; room_index++)
        {
			if (bridge[room_index]->people != NULL)
			{
				wake_countdown--;
				player_found = true;
			}
        }
        
        /*  check to reset counter if no one on bridge*/
        if (player_found == false) wake_countdown=3;
		
		
        if ((wake_countdown<=0) && (mob_state==0)) mob_state = 1; /* awaken mob if it isn't already */
		
	}
	
	switch (mob_state)
    {             
		
	case 0: /* mob is asleep - check for ppl in mobs lair - instant wakeup  */
		
		if ((bridge[0]->people != ch) || (ch->next_in_room != NULL))
		{
			wake_countdown = 0;
			do_wake(ch,"");
			act("$n rises up menacingly above YOU!, flame ripples along its form.", ch, NULL, NULL, TO_ROOM );
			do_yell(ch,"Who is this that disturbs my slumber?");
			mob_state = 2;
		}
		break;
		
	case 1: /* awaken mob */
		do_wake(ch,"");
		act("$n rises up menacingly above YOU!, flame ripples along its form.", ch, NULL, NULL, TO_ROOM );
		do_yell(ch,"Fool's are they that disturb my slumber");
		mob_state = 2;
		break;
		
	case 2: /* mob awake in lair */
		if (ch->position!=POS_FIGHTING)
		{
			do_west(ch,"");
			act("$n rises up menacingly above YOU!, flame ripples along its form.", ch, NULL, NULL, TO_ROOM );
			mob_state = 3;
			
		}
		break;
		
	case 3: /* mob just outside of lair */
		if (ch->position!=POS_FIGHTING)
		{
			do_south(ch,"");
			act("$n rises up menacingly above YOU!, flame ripples along its form.", ch, NULL, NULL, TO_ROOM );
			mob_state = 4;
			
		}
		break;
		
	case 4: /* mob on northern end of bridge */
		if (ch->position!=POS_FIGHTING)
		{
			do_south(ch,"");
			act("$n rises up menacingly above YOU!, flame ripples along its form.", ch, NULL, NULL, TO_ROOM );
			mob_state = 5;
			
		}
		break;
		
	case 5: /* mob on southern end of bridge */
		if (ch->position!=POS_FIGHTING)
		{
			do_south(ch,"");
			act("$n rises up menacingly above YOU!, flame ripples along its form.", ch, NULL, NULL, TO_ROOM );
			mob_state = 6;
			
		}
		break;
		
	case 6: /* mob just south of bridge - turn around and go back up */
		if (ch->position!=POS_FIGHTING)
		{
			do_north(ch,"");
			act("$n rises up menacingly above YOU!, flame ripples along its form.", ch, NULL, NULL, TO_ROOM );
			mob_state = 7;
			
		}
		break;
		
		
	case 7: /* mob on southern end of bridge - returning */
		if (ch->position!=POS_FIGHTING)
		{
			do_north(ch,"");
			act("$n rises up menacingly above YOU!, flame ripples along its form.", ch, NULL, NULL, TO_ROOM );
			mob_state = 8;
			
		}
		break;
		
	case 8: /* mob on northern end of bridge - returning */
		if (ch->position!=POS_FIGHTING)
		{
			do_north(ch,"");
			act("$n rises up menacingly above YOU!, flame ripples along its form.", ch, NULL, NULL, TO_ROOM );
			mob_state = 9;
			
		}
		break;
		
	case 9: /*  mob just north of bridge, west of lair - returning */
		if (ch->position!=POS_FIGHTING)
		{
			do_east(ch,"");
			act("$n rises up menacingly above YOU!, flame ripples along its form.", ch, NULL, NULL, TO_ROOM );
			mob_state = 10; 
			
		}
		break;
		
		
	case 10: /* in lair - going to sleep */
		if (ch->position!=POS_FIGHTING)
		{
			do_sleep(ch,"");
			mob_state = 0; 
			wake_countdown=3; /* reset mob */
			act("$n reclines slowly back into the lava.", ch, NULL, NULL, TO_ROOM );
		}
		break;
		
	default:
		if (ch->position!=POS_FIGHTING)
			return dragon(ch, "fire breath");
		
   }
   return false;	
}

/***************************************************************************/
bool spec_assassin( char_data *ch )
{
    char buf[MSL];
    char_data *victim;
    char_data *v_next;
    int rnd_say;
	
    if ( ch->fighting != NULL )
		return false;
	
    for ( victim = ch->in_room->people; victim != NULL; victim = v_next )
    {
		v_next= victim->next_in_room;
		if (victim->clss != class_lookup("thief"))  
			break;
    }
	
    if ( victim == NULL || victim == ch || IS_IMMORTAL(victim) )
        return false;
    if ( victim->level > ch->level + 7 || IS_NPC(victim))
        return false;
	
    rnd_say = number_range (1, 10);
	
    switch (rnd_say)
    {
	case 6:
		sprintf( buf, "Time to die...");
		break;
	case 7:
		sprintf( buf, "Death is the true end..."); 
		break;
	case 8:
		sprintf( buf, "Welcome to your fate...");
		break;
	case 9:
		sprintf( buf, "Its a good day to die...");
		break;
	case 10:
		sprintf( buf, "Ever dance the dance..."); 
		break;
	default:
		sprintf( buf, "Die!!!");
		break;
    }
    do_say( ch, buf );
	
    multi_hit( ch, victim, gsn_backstab );
    multi_hit( ch, victim, gsn_backstab );
    return true;
}

/*************************************************************************
 *  spec_beggar - Created by Raine & edited by Kalahn - Apr 97           *
 ************************************************************************/
bool spec_beggar( char_data *ch )
{
    char buf[MSL];
    int rnd_say;
    static long last_tick = 0;

    if ( ch->fighting != NULL )
                return false;

    if (tick_counter > last_tick)
    {
        last_tick = tick_counter;
        rnd_say = number_range (1, 10);                
        switch (rnd_say)
        {
             case 6:
                act("$n points at the shimmering doorways.", ch, NULL, NULL, TO_ROOM );
                sprintf( buf, "Blue red green pink, i can never remember which one");
                break;
             case 7:
                act("$n chuckles insanely.", ch, NULL, NULL, TO_ROOM );
                sprintf( buf, "Dance the dance they said, and o how i danced");
                break;
             case 8:
                act("$n mulls over some idea.", ch, NULL, NULL, TO_ROOM );
                sprintf( buf, "Tis funny i could never tell blue or pink apart");
                break;
             case 9:
                act("$n rants and raves.", ch, NULL, NULL, TO_ROOM );
                sprintf( buf, "Aye pinks the one, take the pink road");
                break;
             case 10:
                act("$n smiles coyly.", ch, NULL, NULL, TO_ROOM );
                sprintf( buf, "Beware your next step, it may be your last, so go prepared"); 
                break;
             default:
                act("$n shudders as he rants and raves.", ch, NULL, NULL, TO_ROOM );
                sprintf( buf, "Tis the beast, its the one, walk quick or it will have some fun");                
                break;
        }
        do_say( ch, buf );
    }
    return true;
}

/************************************************************************
 *  spec_summoned_guardian - Created by Raine & Kalahn   - Sept97       *
 ************************************************************************/
bool spec_summoned_guardian( char_data *ch )
{
    char_data *victim;

    /* timer for guardian, timer is approx
       number of ticks guardian exists for */
    if (number_range(1,(int)PULSE_TICK/PULSE_MOBILE) == 1)
        ch->timer--;

    if ( ch->timer<1 )
    {
       act("$n shimmers and fades out of existance.", ch, NULL, NULL, TO_ROOM );
       extract_char( ch, true );
       return false;
    }


    if ( ch->fighting != NULL )
        return false;

    
    for ( victim = ch->in_room->people; victim != NULL; victim = victim->next_in_room)
    {
         // dont activate on a mage, itself or an immortal
         if (victim->clss == class_lookup("mage") || victim == ch || IS_IMMORTAL(victim))
            continue;

         break; // someone is in the room to attack
    }

    if (victim == NULL)
        return false;

    /* dont attack newbies */
    if ( victim->level < 11 )
    {
        do_yell(ch,"Master, someone disturbs you!");
        return false;
    }

    /* dont attack those under 15 levels of the mob */
    if ( victim->level+15 < ch->level)
    {
        do_yell(ch,"Master, someone disturbs you!");
        return false;
    }

    do_say(ch, "The master commands it");
    do_yell(ch,"Master, someone disturbs you!");
    act("$n charges toward you on wings of stone.", ch, NULL, NULL, TO_ROOM );
    do_kill(ch, victim->name);
	
    return true;
}

/************************************************************************
 *  spec_elf_muncher - Created by Raine                  - Sept97       *
 ************************************************************************/
bool spec_elf_muncher( char_data *ch )
{
    char_data *victim;

    if ( ch->fighting != NULL )
    return false;

    
    for ( victim = ch->in_room->people; victim != NULL; victim = victim->next_in_room)
    {
         /* dont activate on imm or self or NPC*/
         if (victim == ch || IS_IMMORTAL(victim) || IS_NPC(victim))
            continue;

         break; /* someone is in the room to attack */
    }

    if (victim == NULL)
        return false;

    // only activate on elves 
    if (victim->race != race_lookup("elf"))
        return false;

    /* dont attack to low a level */
    if ( victim->level < 29 )
       {
          do_yell(ch,"Filthy Elf!  Id kill you if you were not so pathetic");
          return false;
       }
    
    /* yell and smash an elf */
    do_say(ch, "Time to die Elf!");
    do_yell(ch,"Call out the guard, elf kiblits all around!");
    act("$n charges toward you, blood red eyes a flame.", ch, NULL, NULL, TO_ROOM );
    do_kill(ch, victim->name);
    return true;
}

/***************************************************************************/
bool spec_shadow_dragon( char_data *ch )
{
    char_data *victim;
    char_data *v_next;
    char *spell;
    int sn;
	
    if ( ch->position != POS_FIGHTING )
		return false;
	
    for ( victim = ch->in_room->people; victim != NULL; victim = v_next )
    {
		v_next = victim->next_in_room;
		if ( victim->fighting == ch && number_bits( 2 ) == 0 )
			break;
    }
	
    if ( victim == NULL )
		return false;
	
    for ( ;; )
	{
		int min_level;
		
		switch ( number_bits( 4 ) )
		{
		case  0: min_level =  0; spell = "shadow breath";  break;
		case  1: min_level =  3; spell = "vampiric touch"; break;
		case  2: min_level =  7; spell = "energy drain";   break;
		case  3: min_level =  8; spell = "curse";          break;
		case  4: min_level =  0; spell = "shadow breath";  break;
		case  5: min_level =  0; spell = "shadow breath";  break;
		case  6: min_level =  0; spell = "shadow breath";  break;
		case  7: min_level =  0; spell = "shadow breath";  break;
		case  8: min_level =  0; spell = "shadow breath";  break;
		case  9: min_level =  0; spell = "shadow breath";  break;
		case 10: min_level = 20; spell = "wrath";          break;
		default: min_level = 20; spell = "shadow breath";  break;
		}
		
		if ( ch->level >= min_level )
			break;
    }
	
    if ( ( sn = skill_lookup( spell ) ) < 0 )
		return false;
    (*skill_table[sn].spell_fun) ( sn, ch->level, ch, victim,TARGET_CHAR);
    return true;
}

/***************************************************************************/
bool spec_steel_dragon( char_data *ch )
{
    char_data *victim;
    char_data *v_next;
    char *spell;
    int sn;
	
    if ( ch->position != POS_FIGHTING )
		return false;
	
    for ( victim = ch->in_room->people; victim != NULL; victim = v_next )
    {
		v_next = victim->next_in_room;
		if ( victim->fighting == ch && number_bits( 2 ) == 0 )
			break;
    }
	
    if ( victim == NULL )
		return false;
	
    for ( ;; )
	{
		int min_level;
		
		switch ( number_bits( 4 ) )
		{
		case  0: min_level =  0; spell = "steel breath";  break;
		case  1: min_level =  3; spell = "steel breath";  break;
		case  2: min_level =  7; spell = "steel breath";  break;
		case  3: min_level =  8; spell = "heat metal";    break;
		case  4: min_level =  3; spell = "steel breath";  break;
		case  5: min_level =  3; spell = "steel breath";  break;
		case  6: min_level =  3; spell = "steel breath";  break;
		case  7: min_level =  3; spell = "steel breath";  break;
		case  8: min_level =  3; spell = "steel breath";  break;
		case  9: min_level =  3; spell = "steel breath";  break;
		case 10: min_level = 20; spell = "heat metal";    break;
		default: min_level = 20; spell = "steel breath";  break;
		}
		
		if ( ch->level >= min_level )
			break;
    }
	
    if ( ( sn = skill_lookup( spell ) ) < 0 )
		return false;
    (*skill_table[sn].spell_fun) ( sn, ch->level, ch, victim,TARGET_CHAR);
    return true;
}

/***************************************************************************/
bool spec_cast_mean( char_data* ch )
{
	char_data* victim;
	char_data* v_next;
	char *spell;
	int sn;
	
    if ( ( ch->position != POS_FIGHTING ) ||
		( ch->wait > 0 ) ||
		( IS_AFFECTED( ch, AFF_BLIND ) ) ||
		( IS_AFFECTED( ch, AFF2_MUTE ) ) ||
		( IS_AFFECTED2( ch, AFF2_TAUNT ) ) ||
		( IS_AFFECTED2( ch, AFF2_ROAR ) ) ||
		( IS_SET( ch->in_room->affected_by, ROOMAFF_CONE_OF_SILENCE ) ) )
		return false;
	
	for ( victim = ch->in_room->people; victim != NULL; victim = v_next )
	{
		v_next = victim->next_in_room;
		if ( victim->fighting == ch && number_bits( 2 ) == 0 )
			break;
	}
	
	if ( victim == NULL )
		return false;
	
	for ( ;; )
	{
		int min_level;
		
		if ( IS_AFFECTED( ch, AFF_BLIND ) )
		{
			victim = ch;
			min_level = 0;
			spell = "cure blindness";
			break;
		}
		else if ( IS_AFFECTED( ch, AFF2_MUTE ) || 
			IS_SET( ch->in_room->affected_by, ROOMAFF_CONE_OF_SILENCE ) )
		{
			victim = ch;
			min_level = 0;
			spell = "dispel silence";
			break;
		}
		else switch ( number_bits( 4 ) )
		{
			case  0: min_level =  0; spell = "blindness";      break;
			case  1: min_level =  3; spell = "mental implosion";    break;
			case  2: min_level =  7; spell = "natures fury";         break;
			case  3: min_level =  8; spell = "dispel magic";       break;
			case  4: min_level = 11; spell = "ice storm";   break;
			case  5: min_level = 12; spell = "faerie fire";     break;
			case  6: min_level = 13; spell = "heat metal";   break;
			case  7:
			case  8: min_level = 14; spell = "mute";           break;
			case  9: min_level = 15; spell = "frostball";       break;
			case 10: min_level = 20; spell = "spirit lance";         break;
			default: min_level = 20; spell = "improved phantasm";     break;
		}
		
		if ( ch->level >= min_level )
			break;
	}
	
	if ( ( sn = skill_lookup( spell ) ) < 0 )
		return false;
	say_spell(ch, sn, CCT_MAGE);
	(*skill_table[sn].spell_fun) ( sn, ch->level, ch, victim,TARGET_CHAR);
	return true;
}
/***************************************************************************/
bool spec_cast_meaner( char_data* ch )
{
	char_data* victim;
	char_data* v_next;
	char *spell;
	int sn;
	
    if ( ( ch->position != POS_FIGHTING ) ||
		( ch->wait > 0 ) ||
		( IS_AFFECTED( ch, AFF_BLIND ) ) ||
		( IS_AFFECTED( ch, AFF2_MUTE ) ) ||
		( IS_AFFECTED2( ch, AFF2_TAUNT ) ) ||
		( IS_AFFECTED2( ch, AFF2_ROAR ) ) ||
		( IS_SET( ch->in_room->affected_by, ROOMAFF_CONE_OF_SILENCE ) ) )
		return false;
	
	for ( victim = ch->in_room->people; victim != NULL; victim = v_next )
	{
		v_next = victim->next_in_room;
		if ( victim->fighting == ch && number_bits( 2 ) == 0 )
			break;
	}
	
	if ( victim == NULL )
		return false;
	
	for ( ;; )
	{
		int min_level;
		
		if ( IS_AFFECTED( ch, AFF_BLIND ) )
		{
			victim = ch;
			min_level = 0;
			spell = "cure blindness";
			break;
		}
		else if ( IS_AFFECTED( ch, AFF2_MUTE ) || 
			IS_SET( ch->in_room->affected_by, ROOMAFF_CONE_OF_SILENCE ) )
		{
			victim = ch;
			min_level = 0;
			spell = "dispel silence";
			break;
		}
		else switch ( number_bits( 4 ) )
		{
			case  0: min_level =  0; spell = "meteor swarm";      break;
			case  1: min_level =  3; spell = "mental implosion";    break;
			case  2: min_level =  7; spell = "gas breath";         break;
			case  3: min_level =  8; spell = "dispel magic";       break;
			case  4: min_level = 11; spell = "elemental storm";   break;
			case  5: min_level = 12; spell = "holy fire";     break;
			case  6: min_level = 13; spell = "heat metal";   break;
			case  7: min_level = 13; spell = "fire breath"; break;
			case  8: min_level = 14; spell = "lightning breath";           break;
			case  9: min_level = 15; spell = "steam breath";       break;
			case 10: min_level = 20; spell = "spirit lance";         break;
			default: min_level = 20; spell = "mind thrust";     break;
		}
		
		if ( ch->level >= min_level )
			break;
	}
	
	if ( ( sn = skill_lookup( spell ) ) < 0 )
		return false;
	say_spell(ch, sn, CCT_MAGE);
	(*skill_table[sn].spell_fun) ( sn, ch->level, ch, victim,TARGET_CHAR);
	return true;
}
/***************************************************************************/
bool spec_master_thief( char_data* ch )
{
    char_data* victim;
    char_data* v_next;
    OBJ_DATA *obj;
    int percent, skill;
	
    if ( ( ch->position < POS_STANDING ) ||
		( ch->wait > 0 ) ||
		( IS_AFFECTED( ch, AFF_BLIND ) ) ||
		( IS_AFFECTED2( ch, AFF2_TAUNT ) ) ||
		( IS_AFFECTED2( ch, AFF2_ROAR ) ) )
		return false;
	
    for ( victim = ch->in_room->people; victim != NULL; victim = v_next )
    {
		v_next = victim->next_in_room;
		
        if ( IS_NPC(victim) ) /* Only PC's are targets */
            return false;
		
        if ( is_safe( ch, victim ) ) /* Only viable targets */
            return false;
		
        if ( victim->level >= LEVEL_IMMORTAL /* Don't mess with IMMs */
			||   number_bits( 5 ) != 0 
			||   !can_see(ch,victim) )
			continue;
		
        skill = 40 + 2 * ch->level;
		percent  = number_percent();
		
        /* Some sanity checking below, NPC's should NOT be targets */
        if ( !IS_NPC( victim ) && get_skill(victim, gsn_awareness) >= 1 )
        {
            percent += victim->pcdata->learned[gsn_awareness]/2;
            if ( !IS_AWAKE( victim ) )
                do_wake(victim, "");
            check_improve(victim, gsn_awareness, true, 14);
        }
		
        percent  += (!IS_AWAKE(victim) ? -50 : !can_see(victim, ch) ? -25 : 10);
		
        if ( percent+victim->level-ch->level > skill )
        {
		/*
		* Failure.
			*/
            act( "$n tried to steal from you!\r\n", ch, NULL, victim, TO_VICT    );
            act( "$n tried to steal from $N!\r\n",  ch, NULL, victim, TO_NOTVICT );
            return false;
        }
        else
        {
            switch ( number_range(1, 2) )
            {
				int gold, silver;
				
			case 1:
				
				gold = victim->gold * number_range(1, ch->level) / 160;
				silver = victim->silver * number_range(1, ch->level) / 160;
				if ( gold <= 0 && silver <= 0 )
					return false;
				
				ch->gold       += gold;
				ch->silver     += silver;
				victim->silver -= silver;
				victim->gold   -= gold;
				return true;
				
			case 2:
				
				if ( ( obj = get_random_obj( victim ) ) == NULL
					|| !can_see_obj( ch, obj ) )
					return false;
				
				obj_from_char( obj );
				obj_to_char( obj, ch );
				return true;
			}
		}
	}
	return false;
}
/***************************************************************************/
bool spec_charmer( char_data* ch )
{
    char_data* victim;
    char_data* v_next;
    char buf[MSL];

    if ( ch->position != POS_FIGHTING )
    {
       switch ( number_bits( 3 ) ) 
	 {
       case 0:
	  sprintf( buf, "all sing %s", ch->name );
          do_order( ch, buf ); // a chance to get free here
          break;
       case 1:
          break;
       case 2:
          break;
       case 3:
          do_order( ch, "all remove dagger" );
	    sprintf( buf, "all give dagger %s", ch->name );
          do_order( ch, buf );
          break;
       case 4:
          do_order( ch, "all remove sword" );
	    sprintf( buf, "all give sword %s", ch->name );
          do_order( ch, buf );
          break;
       case 5:
          do_order( ch, "all remove mace" );
	    sprintf( buf, "all give mace %s", ch->name );
          do_order( ch, buf );
          break;
       case 6:
          do_order( ch, "all drop all" );
          break;
       case 7:
	    sprintf( buf, "all cast 'cure light' %s", ch->name );
          do_order( ch, buf );
          break;
       };

       return true;
       }

    for ( victim = ch->in_room->people; victim != NULL; victim = v_next )
    {
        v_next = victim->next_in_room;
        if ( victim->fighting == ch && number_bits( 2 ) == 0 )
            break;
    }

    if ( victim == NULL )
        return false;

    if (IS_AFFECTED2(ch, AFF2_MUTE) || IS_SET( ch->in_room->affected_by, ROOMAFF_CONE_OF_SILENCE ))
	return false;

    act( "$n begins playing a new, beautiful song.", ch, NULL, NULL,TO_ROOM );
    spell_charm_person(gsn_charm_person, ch->level, ch, victim, TARGET_CHAR );
    if (IS_AFFECTED(victim, AFF_CHARM))
       stop_fighting( victim, true );

    return true;
}
/***************************************************************************/
bool spec_troll_member( char_data* ch)
{
    char_data* vch;
    char_data* victim = 0;
    int count = 0;
    char *message;

    if (!IS_AWAKE(ch) || IS_AFFECTED(ch,AFF_CALM) || ch->in_room == NULL 
    ||  IS_AFFECTED(ch,AFF_CHARM) || ch->fighting != NULL)
	return false;

    // find an ogre to beat up 
    for (vch = ch->in_room->people;  vch != NULL;  vch = vch->next_in_room)
    {
	if (!IS_NPC(vch) || ch == vch)
	    continue;

	if (vch->pIndexData->vnum == MOB_VNUM_PATROLMAN)
	    return false;

	if (vch->pIndexData->group == GROUP_VNUM_OGRES
	&&  ch->level > vch->level - 2 && !is_safe(ch,vch))
	{
	    if (number_range(0,count) == 0)
		victim = vch;

	    count++;
	}
    }

    if (victim == NULL)
	return false;

	// say something, then raise hell 
    switch (number_range(0,6))
    {
	default:  message = NULL; 	break;
	case 0:	message = "$n yells 'I've been looking for you, punk!'";
		break;
	case 1: message = "With a scream of rage, $n attacks $N.";
		break;
	case 2: message = 
		"$n says 'What's slimy Ogre trash like you doing around here?'";
		break;
	case 3: message = "$n cracks his knuckles and says 'Do ya feel lucky?'";
		break;
	case 4: message = "$n says 'There's no cops to save you this time!'";
		break;	
	case 5: message = "$n says 'Time to join your brother, spud.'";
		break;
	case 6: message = "$n says 'Let's rock.'";
		break;
    }

    if (message != NULL)
    	act(message,ch,NULL,victim,TO_ALL);
    multi_hit( ch, victim, TYPE_UNDEFINED );
	 return true;
}

/***************************************************************************/
bool spec_ogre_member( char_data* ch)
{
    char_data* vch;
    char_data* victim = 0;
    int count = 0;
    char *message;
 
    if (!IS_AWAKE(ch) || IS_AFFECTED(ch,AFF_CALM) || ch->in_room == NULL
    ||  IS_AFFECTED(ch,AFF_CHARM) || ch->fighting != NULL)
        return false;

    // find an troll to beat up 
    for (vch = ch->in_room->people;  vch != NULL;  vch = vch->next_in_room)
	 {
        if (!IS_NPC(vch) || ch == vch)
            continue;
 
        if (vch->pIndexData->vnum == MOB_VNUM_PATROLMAN)
            return false;
 
        if (vch->pIndexData->group == GROUP_VNUM_TROLLS
        &&  ch->level > vch->level - 2 && !is_safe(ch,vch))
		  {
            if (number_range(0,count) == 0)
                victim = vch;
 
            count++;
        }
    }
 
    if (victim == NULL)
        return false;
 
    // say something, then raise hell
    switch (number_range(0,6))
    {
	default: message = NULL;	break;
		  case 0: message = "$n yells 'I've been looking for you, punk!'";
                break;
        case 1: message = "With a scream of rage, $n attacks $N.'";
                break;
        case 2: message =
                "$n says 'What's Troll filth like you doing around here?'";
                break;
        case 3: message = "$n cracks his knuckles and says 'Do ya feel lucky?'";
                break;
		  case 4: message = "$n says 'There's no cops to save you this time!'";
                break;
        case 5: message = "$n says 'Time to join your brother, spud.'";
                break;
        case 6: message = "$n says 'Let's rock.'";
                break;
    }
 
    if (message != NULL)
    	act(message,ch,NULL,victim,TO_ALL);
    multi_hit( ch, victim, TYPE_UNDEFINED );
    return true;
}
/***************************************************************************/
bool spec_questmaster (char_data* ch)
{
    if (ch->fighting != NULL) return spec_cast_mage( ch );
    return false;
}
/***************************************************************************/
bool spec_clan_transport( char_data* ch )
{
    char_data* victim;
    char_data* v_next;
	
    if ( !IS_AWAKE(ch) || ch->fighting != NULL )
		return false;
	
    for ( victim = ch->in_room->people; victim != NULL; victim = v_next )
    {
		v_next = victim->next_in_room;
		
        if ( victim == NULL )
			return false;
        if ( IS_NPC(victim) )
            return false;
		
		act("$n eyes glow brightly for a moment.",ch,NULL,victim,TO_ALL);
		
	    ROOM_INDEX_DATA *location;

		int recall_vnum=get_recallvnum(ch);

		if ( ( location = get_room_index( recall_vnum ) ) == NULL )
		{
			ch->println("You are completely lost.");
			
			if ( ( location = get_room_index( ROOM_VNUM_OOC ) ) == NULL)
			{
				ch->printf("BUG: Cant find the main ooc room (vnum = %d)\r\n"
					"Please report this to an admin.\r\n", ROOM_VNUM_OOC);
				return false;
			}
			else
			{
				if (IS_SET(location->room_flags, ROOM_OOC))
				{
					ch->println("Taking you to the main OOC room since your normal recall doesnt exist.");
				}
				else
				{
					ch->printf("BUG: Taking you to the main ooc room (vnum = %d)\r\n"
						"This room SHOULD be an OOC room - please report this bug to an admin.\r\n", ROOM_VNUM_OOC);
				}
			}	
		}

        char_from_room(victim);
        char_to_room(victim, location);
		do_look( victim, "auto" );
        return true;
    }
    return false;
}
/***************************************************************************
 !!!!!!!!!!!!!!!!!!!!!!!OBJ SPECIAL FUNCTIONS BELOW HERE!!!!!!!!!!!!!!!!!!!!
 ***************************************************************************/
bool spec_obj_test( OBJ_DATA *, char_data *)
{
    act("SAYS HELLO!!!!",NULL,NULL,NULL,TO_ROOM);
    act("SAYS HELLO!!!!",NULL,NULL,NULL,TO_CHAR);
    return true;
}

/***************************************************************************/
/***************************************************************************/
/***************************************************************************/
/***************************************************************************/