daleken/
daleken/data/notes/
daleken/data/player/
daleken/data/system/poses/
daleken/doc/Homepage/images/
daleken/log/
/*___________________________________________________________________________*
   )()(			  DalekenMUD 1.12 (C) 2000			)()(
   `]['		       by Martin Thomson, Lee Brooks,			`]['
    ||		       Ken Herbert and David Jacques			 ||
    || ----------------------------------------------------------------- ||
    || Envy Diku Mud improvements copyright (C) 1994 by Michael Quan,	 ||
    || David Love, Guilherme 'Willie' Arnold, and Mitchell Tse.		 ||
    || Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael	 ||
    || Chastain, Michael Quan, and Mitchell Tse.			 ||
    || Original Diku Mud copyright (C) 1990, 1991			 ||
    || by Sebastian Hammer, Michael Seifert, Hans Henrik St{rfeldt,	 ||
    || Tom Madsen, and Katja Nyboe.					 ||
    || ----------------------------------------------------------------- ||
    || Any use of this software must follow the licenses of the		 ||
    || creators.  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.					 ||
    || ----------------------------------------------------------------- ||
    ||                             special.c                             ||
    || Contains hardcoded special functions for mobiles.                 ||
 *_/<>\_________________________________________________________________/<>\_*/


#include "mud.h"

/**************** SPECIAL FUNCTION WRITERS NOTE! *****************
 *
 * The following functions can be activated in the following
 * formats:
 *
 * SPEC_AUTONOMOUS: happens like the regular spec functions
 *		    second argument NULL
 *		    return true if they actually did something
 * SPEC_DEATH: happens when the mob dies
 *	       second argument the person who killed them
 *	       return true if you created a corpse
 * SPEC_TELL: happens when you say something or tell them something
 *	      second argument is who said it
 *	      return true if you acted upon the words
 *	      NOTE: to find out what was said you have to check
 *		    player->desc->inlast, use strcpy and check if
 *		    player->desc exists first
 * SPEC_GIVE: happens when you give the mob something
 *	      second argument is who gave the item
 *	      return value is irrelvant, so return true if you did stuff
 *	      NOTE: you can check what they gave you by checking your
 *		    own inventory, but make sure you remove the item
 *		    afterwards so it doesn't interfere in future.
 * SPEC_ENTER: happens when a player enters the room
 *	       second argument is who has entered
 *	       return doesn't matter, so return true if you acted
 *
 * SPEC_ATTACK: happens when someone tries to attack the mobile,
 *		the return is true if the mob is safe so you can
 *		stop players from attacking particular mobiles
 *		by giving them spec_safe or something which simply
 *		returns TRUE
 *
 * That should just about cover it for now, this I hope will actually
 * add to your capability for creating intelligent areas.
 *
 * A few additional hints, if you want something to happen only after
 * a reboot, try using a static variable in your spec_fun, I wouldn't
 * suggest you use this too often though, it makes a mess of the stack.
 *
 * --Symposium, coding whatever you like : )
 */

/*
 * External functions.
 */
DECLARE_DO_FUN( mp_peace );

/*
 * The following special functions are available for mobiles.
 */
DECLARE_SPEC_FUN( spec_null		);
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_cast_adept	);
DECLARE_SPEC_FUN( spec_cast_cleric	);
DECLARE_SPEC_FUN( spec_cast_ghost	);
DECLARE_SPEC_FUN( spec_cast_judge	);
DECLARE_SPEC_FUN( spec_cast_mage	);
DECLARE_SPEC_FUN( spec_cast_psionicist	);
DECLARE_SPEC_FUN( spec_cast_undead	);
DECLARE_SPEC_FUN( spec_executioner	);
DECLARE_SPEC_FUN( spec_fido		);
DECLARE_SPEC_FUN( spec_guard		);
DECLARE_SPEC_FUN( spec_janitor		);
DECLARE_SPEC_FUN( spec_poison		);
DECLARE_SPEC_FUN( spec_spider		);
DECLARE_SPEC_FUN( spec_repairman	);
DECLARE_SPEC_FUN( spec_thief		);
DECLARE_SPEC_FUN( spec_weevil		);	/* Daleken */
DECLARE_SPEC_FUN( spec_cast_god		);	/* Daleken */
DECLARE_SPEC_FUN( spec_peacemaker	);	/* Daleken */
DECLARE_SPEC_FUN( spec_drunk		);	/* Daleken */
DECLARE_SPEC_FUN( spec_deaf		);	/* Daleken */
DECLARE_SPEC_FUN( spec_safe		);	/* Daleken */
DECLARE_SPEC_FUN( spec_religion_recruit	);	/* Daleken */
DECLARE_SPEC_FUN( spec_necro		);	/* Daleken */
DECLARE_SPEC_FUN( spec_changeling	);	/* Daleken */
DECLARE_SPEC_FUN( death_explode		);
DECLARE_SPEC_FUN( death_ghost		);


/*
 * Special function table.
 */
const struct spec_type spec_table[] =
{
    /* leave this top one alone please */
    {
	spec_null, "spec_null",
	SPEC_NULL, NULL, 0
    },

    {
	spec_breath_any, "spec_breath_any",
	SPEC_FIGHT, "$N has REALLY bad breath.",
	25
    },

    {
	spec_breath_acid, "spec_breath_acid",
	SPEC_FIGHT, "$N has REALLY bad breath.",
	20
    },

    {
	spec_breath_fire, "spec_breath_fire",
	SPEC_FIGHT, "$N has REALLY bad breath.",
	20
    },

    {
	spec_breath_frost, "spec_breath_frost",
	SPEC_FIGHT, "$N has REALLY bad breath.",
	20
    },

    {
	spec_breath_gas, "spec_breath_gas",
	SPEC_FIGHT, "$N has REALLY bad breath.",
	20
    },

    {
	spec_breath_lightning, "spec_breath_lightning",
	SPEC_FIGHT, "$N has REALLY bad breath.",
	20
    },

    {
	spec_cast_adept, "spec_cast_adept",
	SPEC_AUTONOMOUS, "$N looks kind and benevolent.",
	-40
    },

    {
	spec_cast_cleric, "spec_cast_cleric",
	SPEC_FIGHT, "$N looks wise.",
	20
    },

    {
	spec_cast_ghost, "spec_cast_ghost",
	SPEC_FIGHT, "$N is slightly see through.",
	20
    },

    {
	spec_cast_judge, "spec_cast_judge",
	SPEC_FIGHT, "$N looks very stern.",
	20
    },

    {
	spec_cast_mage, "spec_cast_mage",
	SPEC_FIGHT, "$N looks very intelligent.",
	30
    },

    {
	spec_cast_psionicist, "spec_cast_psionicist",
	SPEC_FIGHT, "$N has a penetrating gaze, as if $E can read your mind.",
	35
    },

    {
	spec_cast_undead, "spec_cast_undead",
	SPEC_FIGHT, "$N looks VERY old.",
	30
    },

    {
	spec_executioner, "spec_executioner",
	SPEC_AUTONOMOUS, "$N is wearing a black hood.",
	0
    },

    {
	spec_fido, "spec_fido",
	SPEC_AUTONOMOUS, "$N is hungry and will eat ANYTHING!!!",
	0
    },

    {
	spec_guard, "spec_guard",
	SPEC_AUTONOMOUS, "$N stands tall and proud, guarding all that is good.",
	0
    },

    {
	spec_janitor, "spec_janitor",
	SPEC_AUTONOMOUS, "$N looks neat and fussy.",
	0
    },

    {
	spec_poison, "spec_poison",
	SPEC_FIGHT, "$N has sharp fangs dripping poison.",
	5
    },

    {
	spec_spider, "spec_spider",
	SPEC_FIGHT, "$N has eight spidly legs and sharp fangs.",
	8
    },

    {
	spec_repairman, "spec_repairman",
	SPEC_AUTONOMOUS, "$N carries a toolbox and shows a bit of bum-crack.",
	0
    },

    {
	spec_thief, "spec_thief",
	SPEC_AUTONOMOUS, "$N is a shifty looking character.",
	5
    },

    {
	spec_weevil, "spec_weevil",
	SPEC_AUTONOMOUS, "$N will nick something and run away giggling.",
	10
    },

    {
	spec_cast_god, "spec_cast_god",
	SPEC_FIGHT, "$N controls all the power in the world.",
	40
    },

    {
	spec_peacemaker, "spec_peacemaker",
	SPEC_AUTONOMOUS, "$N proclaims $S distaste for battle.",
	-25
    },

    {
	spec_drunk,	"spec_drunk",
	SPEC_AUTONOMOUS, "$N's haunted eyes stare at you from beyond the grave.",
	15
    },

    {
	spec_necro,	"spec_necro",
	SPEC_AUTONOMOUS, "$N's haunted eyes stare at you from beyond the grave.",
	15
    },

    {
	spec_changeling, "spec_changeling",
	SPEC_AUTONOMOUS, "$N's shape shimmer slightly as you look at it.",
	25
    },

    {
	spec_deaf, "spec_deaf",
	SPEC_TELL, "$N cleans $S ears and says 'WHATCHA SAY?'",
	0
    },

    {
	spec_safe,    "spec_safe",
	SPEC_ATTACK, "$N behaves as though $E has complete impunity.",
	0
    },

    {
	spec_religion_recruit,	"spec_religion_recruit",
	SPEC_TELL,	"$N's eyes show a religious fervour.",
	-30
    },

    {
	death_explode, "death_explode",
	SPEC_DEATH, "$N looks a little volatile.",
	10
    },

    {
	death_ghost, "death_ghost",
	SPEC_DEATH, "$N is slightly see through.",
	0
    },


    { NULL, "", SPEC_NULL, NULL }
};



/*****************************************************************************
 Name:		spec_string
 Purpose:	Given a function, return the appropriate name.
 Called by:	medit_show( olc_act.c )

char *spec_string( SPEC_FUN *fun )
{
    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;
}
****************************************************************************/


/*****************************************************************************
 Name:		spec_lookup
 Purpose:	Given a name, return the appropriate spec fun.
 Called by:	do_mset (act_wiz.c) load_specials,reset_area (db.c)
 ****************************************************************************/
int spec_lookup( const char *name )	/* OLC */
{
    int cmd;

    for( cmd = 0; *spec_table[cmd].spec_name; cmd++ )	/* OLC 1.1b */
	if( !str_cmp( name, spec_table[cmd].spec_name ) )
	    return cmd;

    return 0;
}


/*
 * A special function that is used for mercenaries who kill mobiles.
 * After they can everything from the corpse they need to sort out all the
 * junk, this isn't all that smart but neither is the average mercenary.
 */
void sort_inventory( CHAR_DATA *ch )
{
    OBJ_DATA *obj, *obj_next, *wobj;
    int i;
    do_wear( ch, "all" );
    for( obj = ch->carrying; obj; obj = obj_next )
    {
	obj_next = obj->next_content;
	if( obj->deleted || obj->wear_loc != WEAR_NONE )
	    continue;
	if( obj->item_type != ITEM_ARMOUR && obj->item_type != ITEM_WEAPON )
	{
	    act( "$n drop$% $p in distaste.", ch, obj, NULL, TO_ALL );
	    obj_from_char( obj );
	    obj_to_room( obj, ch->in_room );
	    continue;
	}
	for( i = 0; i < MAX_WEAR; ++i )
	{
	    bool better = FALSE;

	    if( !CAN_WEAR( obj, wear_table[i].wear_flag )
		|| obj->level > ch->level + 3 )
		continue;

	    if( !( wobj = get_eq_char( ch, i ) ) )
		continue;
	    if( wobj->item_type == obj->item_type )
	    {
		if( obj->item_type == ITEM_WEAPON
		    && obj->value[1] + obj->value[2]
		    > wobj->value[1] + wobj->value[2] )
		    better = TRUE;
		if( obj->item_type == ITEM_ARMOUR
		    && ( obj->value[1] < 0
			 || ( get_size( ch ) + 10 >= obj->value[1]
			      && get_size( ch ) - 10 <= obj->value[1] ) )
		    && obj->value[0] > wobj->value[0] )
		    better = TRUE;
	    }
	    if( better || ( wobj->item_type != ITEM_ARMOUR
			    && wobj->item_type != ITEM_WEAPON ) )
	    {
		act( "&b$n take$% $p off and swap$% it for $P.",
		     ch, wobj, obj, TO_ALL );
		unequip_char( ch, wobj );
		obj_from_char( wobj );
		obj_to_room( wobj, ch->in_room );
		equip_char( ch, obj, i );
		break;
	    }
	}
    }
}


/*
 * Core procedure for dragons.
 */
bool dragon( CHAR_DATA *ch, const char *spell_name )
{
    CHAR_DATA *victim;
    int sn;

    if( ch->position != POS_FIGHTING || IS_AFFECTED( ch, AFF_MIND_MIST ) )
	return FALSE;

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

    if( !victim )
	return FALSE;

    if( ( sn = skill_lookup( spell_name ) ) < 0 )
	return FALSE;
    ( *skill_table[sn].spell_fun ) ( sn, ch->level, ch, victim );
    return TRUE;
}



/*
 * Special procedures for mobiles.
 */
bool spec_null( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    return FALSE;
}

bool spec_breath_any( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    switch( number_bits( 3 ) )
    {
    case 0:
	return spec_breath_fire( ch, NULL, SPEC_AUTONOMOUS, NULL );
    case 1:
    case 2:
	return spec_breath_lightning( ch, NULL, SPEC_AUTONOMOUS, NULL );
    case 3:
	return spec_breath_gas( ch, NULL, SPEC_AUTONOMOUS, NULL );
    case 4:
	return spec_breath_acid( ch, NULL, SPEC_AUTONOMOUS, NULL );
    case 5:
    case 6:
    case 7:
	return spec_breath_frost( ch, NULL, SPEC_AUTONOMOUS, NULL );
    }

    return FALSE;
}



bool spec_breath_acid( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    return dragon( ch, "acid breath" );
}



bool spec_breath_fire( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    return dragon( ch, "fire breath" );
}



bool spec_breath_frost( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    return dragon( ch, "frost breath" );
}



bool spec_breath_gas( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    int sn;

    if( ch->position != POS_FIGHTING )
	return FALSE;

    if( ( sn = skill_lookup( "gas breath" ) ) < 0 )
	return FALSE;
    ( *skill_table[sn].spell_fun ) ( sn, ch->level, ch, NULL );
    return TRUE;
}



bool spec_breath_lightning( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    return dragon( ch, "lightning breath" );
}


bool spec_cast_adept( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    CHAR_DATA *victim;

    if( ch->position < POS_FIGHTING  || ch->fighting )
	return FALSE;

    if( IS_AFFECTED( ch, AFF_MUTE )
	|| IS_SET( race_table[ch->race].race_abilities, RACE_MUTE )
	|| IS_SET( ch->in_room->room_flags, ROOM_CONE_OF_SILENCE )
	|| IS_AFFECTED( ch, AFF_MIND_MIST ) )
	return FALSE;

    for( victim = ch->in_room->people; victim; victim = victim->next_in_room )
    {
	if( victim != ch && can_see( ch, victim ) && number_bits( 1 ) == 0 )
	    break;
    }

    if( !victim || IS_NPC( victim ) )
	return FALSE;

    if( victim->level > ch->level - 18 )
    {
	return FALSE;
    }

    switch( number_bits( 3 ) )
    {
    case 0:
	act( "$n utters the word 'kcud'.", ch, NULL, NULL, TO_ROOM );
	spell_armour( skill_lookup( "armour" ), ch->level, ch, victim );
	return TRUE;

    case 1:
	act( "$n utters the word 'eseeg'.", ch, NULL, NULL, TO_ROOM );
	spell_bless( skill_lookup( "bless" ), ch->level, ch, victim );
	return TRUE;

    case 2:
	act( "$n utters the word 'nekcihc'.", ch, NULL, NULL, TO_ROOM );
	spell_cure_blindness( skill_lookup( "cure blindness" ),
			     ch->level, ch, victim );
	return TRUE;

    case 3:
	act( "$n utters the word 'yekrut'.", ch, NULL, NULL, TO_ROOM );
	spell_cure( skill_lookup( "cure" ), ch->level, ch, victim );
	return TRUE;

    case 4:
	act( "$n utters the words 'liauq'.", ch, NULL, NULL, TO_ROOM );
	spell_cure_poison( skill_lookup( "cure poison" ),
			  ch->level, ch, victim );
	return TRUE;

    case 5:
	act( "$n utters the words 'naws'.", ch, NULL, NULL, TO_ROOM );
	spell_endurance( skill_lookup( "endurance" ), ch->level, ch, victim );
	return TRUE;

    case 6:
	act( "$n utters the words 'lwof'.", ch, NULL, NULL, TO_ROOM );
	spell_combat_mind( skill_lookup( "combat mind" ), ch->level, ch,
			  victim );
	return TRUE;
    }

    return FALSE;
}



bool spec_cast_cleric( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    CHAR_DATA *victim;
    const char *spell;
    int sn;

    if( ch->position != POS_FIGHTING )
	return FALSE;

    if( IS_AFFECTED( ch, AFF_MUTE )
	|| IS_AFFECTED( ch, AFF_MIND_MIST )
	|| IS_SET( race_table[ch->race].race_abilities, RACE_MUTE )
	|| IS_SET( ch->in_room->room_flags, ROOM_CONE_OF_SILENCE ) )
	return FALSE;

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

    if( !victim )
	return FALSE;

    for( ;; )
    {
	int min_level;

	switch( number_bits( 4 ) )
	{
	case 0:	    min_level = 0;	    spell = "blindness";    break;
	case 1:	    min_level = 0;	    spell = "hex";	    break;
	case 2:	    min_level = 7;	    spell = "cause serious"; break;
	case 3:	    min_level = 11;	    spell = "faerie fire";  break;
	case 4:	    min_level = 23;	    spell = "harm";	    break;
	case 5:	    min_level = 25;	    spell = "mute";	    break;
	case 6:	    min_level = 26;	    spell = "flamestrike";  break;
	case 7:	    min_level = 30;	    spell = "earthquake";   break;
	case 8:	    min_level = 33;	    spell = "dispel magic"; break;
	case 9:     min_level = 50;	    spell = "tangleweed";   break;
	default:    min_level = 36;	    spell = "condemn";  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 );
    return TRUE;
}



bool spec_cast_judge( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    CHAR_DATA *victim;
    int sn;

    if( ch->position != POS_FIGHTING )
	return FALSE;

    if( IS_AFFECTED( ch, AFF_MUTE )
	|| IS_AFFECTED( ch, AFF_MIND_MIST )
	|| IS_SET( race_table[ch->race].race_abilities, RACE_MUTE )
	|| IS_SET( ch->in_room->room_flags, ROOM_CONE_OF_SILENCE ) )
	return FALSE;

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

    if( !victim )
	return FALSE;

    if( ( sn = skill_lookup( "high explosive" ) ) < 0 )
	return FALSE;
    ( *skill_table[sn].spell_fun ) ( sn, ch->level, ch, victim );
    return TRUE;
}



bool spec_cast_mage( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    CHAR_DATA *victim;
    const char *spell;
    int sn;

    if( ch->position != POS_FIGHTING )
	return FALSE;

    if( IS_AFFECTED( ch, AFF_MUTE )
	|| IS_AFFECTED( ch, AFF_MIND_MIST )
	|| IS_SET( race_table[ch->race].race_abilities, RACE_MUTE )
	|| IS_SET( ch->in_room->room_flags, ROOM_CONE_OF_SILENCE ) )
	return FALSE;

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

    if( !victim )
	return FALSE;

    for( ;; )
    {
	int min_level;

	switch( number_bits( 5 ) )
	{
	case 0:
	case 1:	    min_level = 0;	spell = "magic missile"; break;
	case 2:	    min_level = 5;	spell = "freeze";	break;
	case 3:	    min_level = 8;	spell = "faerie fire";	break;
	case 4:	    min_level = 8;	spell = "blindness";	break;
	case 5:	    min_level = 11;	spell = "weakness";	break;
	case 6:	    min_level = 14;	spell = "hex";	break;
	case 7:	    min_level = 15;	spell = "burn";		break;
	case 8:	    min_level = 19;	spell = "shock";	break;
	case 9:	    min_level = 25;	spell = "colour spray";	break;
	case 10:
	case 11:    min_level = 26;	spell = "dispel magic";	break;
	case 12:
	case 13:    min_level = 29;	spell = "lightning bolt"; break;
	case 14:    min_level = 30;	spell = "blizzard";	break;
	case 15:    min_level = 30;	spell = "inferno";	break;
	case 16:    min_level = 35;	spell = "web";		break;
	case 17:    min_level = 36;	spell = "ice lance";	break;
	case 18:    case 19:
	case 20:    min_level = 37;	spell = "fireball";	break;
	case 21:    min_level = 38;	spell = "teleport";	break;
	case 22:    min_level = 150;	spell = "disintegrate";	break;
	default:    min_level = 28;	spell = "acid blast";	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 );
    return TRUE;
}



bool spec_cast_undead( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    CHAR_DATA *victim;
    const char *spell;
    int sn;

    if( ch->position != POS_FIGHTING || IS_AFFECTED( ch, AFF_MIND_MIST ) )
	return FALSE;

    if( IS_AFFECTED( ch, AFF_MUTE )
	|| IS_SET( race_table[ch->race].race_abilities, RACE_MUTE )
	|| IS_SET( ch->in_room->room_flags, ROOM_CONE_OF_SILENCE ) )
	return FALSE;

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

    if( !victim )
	return FALSE;

    for( ;; )
    {
	int min_level;

	switch( number_bits( 4 ) )
	{
	case 0:
	    min_level = 0;
	    spell = "hex";
	    break;
	case 1:
	    min_level = 3;
	    spell = "weaken";
	    break;
	case 2:
	    min_level = 6;
	    spell = "freeze";
	    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:
	case 9:
	case 10:
	    if( !str_cmp( race_table[ch->race].name, "Vampire" ) )
	    {
		min_level = 24;
		spell = "vampiric bite";
		break;
	    }
	default:
	    min_level = 24;
	    spell = "gate";
	    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 );
    return TRUE;
}



bool spec_executioner( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    CHAR_DATA *victim;
    char buf[MAX_STRING_LENGTH];

    if( !IS_AWAKE( ch ) || ch->fighting )
	return FALSE;

    for( victim = ch->in_room->people; victim; victim = victim->next_in_room )
    {
	if( victim->deleted )
	    continue;

	if( victim->level > LEVEL_HERO )
	    continue;

	if( !IS_NPC( victim ) && xIS_SET( victim->act, PLR_OUTLAW ) )
	    break;
    }

    if( !victim )
	return FALSE;

    sprintf( buf, "%s is an OUTLAW!  PROTECT THE INNOCENT!  MORE BLOOOOD!!!",
	    victim->name );
    do_shout( ch, buf );
    multi_hit( ch, victim, TYPE_UNDEFINED );
/* -- disabled, no need
    char_to_room( create_mobile( get_mob_index( MOB_VNUM_CITYGUARD ) ),
		 ch->in_room );
    char_to_room( create_mobile( get_mob_index( MOB_VNUM_CITYGUARD ) ),
		 ch->in_room );
*/
    return TRUE;
}



bool spec_fido( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    OBJ_DATA *obj;
    OBJ_DATA *obj_next;
    OBJ_DATA *corpse;
    OBJ_DATA *corpse_next;

    if( !IS_AWAKE( ch ) )
	return FALSE;

    for( corpse = ch->in_room->contents; corpse; corpse = corpse_next )
    {
	corpse_next = corpse->next_content;
	if( corpse->deleted )
	    continue;
	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;
	    if( obj->deleted )
		continue;
	    obj_from_obj( obj );
	    obj_to_room( obj, ch->in_room );
	}
	extract_obj( corpse );
	return TRUE;
    }

    return FALSE;
}



bool spec_guard( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    CHAR_DATA *victim;
    CHAR_DATA *ech;
    char buf[MAX_STRING_LENGTH];
    int max_evil;

    if( !IS_AWAKE( ch ) || ch->fighting )
	return FALSE;

    max_evil = 300;
    ech = NULL;

    for( victim = ch->in_room->people; victim; victim = victim->next_in_room )
    {
	if( victim->deleted )
	    continue;

	if( victim->level > LEVEL_HERO )
	    continue;

	if( !IS_NPC( victim ) && xIS_SET( victim->act, PLR_OUTLAW ) )
	    break;

	if( victim->fighting
	    && victim->fighting != ch
	    && victim->alignment < max_evil )
	{
	    max_evil = victim->alignment;
	    ech = victim;
	}
    }

    if( victim )
    {
	sprintf( buf, "%s is an OUTLAW!	 PROTECT THE INNOCENT!!	 BANZAI!!",
		victim->name );
	do_shout( ch, buf );
	multi_hit( ch, victim, TYPE_UNDEFINED );
	return TRUE;
    }

    if( ech )
    {
	act( "$n screams 'PROTECT THE INNOCENT!!  BANZAI!!",
	    ch, NULL, NULL, TO_ROOM );
	multi_hit( ch, ech, TYPE_UNDEFINED );
	return TRUE;
    }

    return FALSE;
}



bool spec_janitor( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    OBJ_DATA *trash;
    OBJ_DATA *trash_next;

    if( !IS_AWAKE( ch ) )
	return FALSE;

    for( trash = ch->in_room->contents; trash; trash = trash_next )
    {
	trash_next = trash->next_content;
	if( trash->deleted || !IS_SET( trash->wear_flags, ITEM_TAKE )
	    || !can_see_obj( 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_poison( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    CHAR_DATA *victim;

    if( ch->position != POS_FIGHTING
	|| !( victim = ch->fighting )
	|| number_percent( ) > 2 * ch->level )
	return FALSE;

    act( "You bite $N!", ch, NULL, victim, TO_CHAR );
    act( "$n bites you!", ch, NULL, victim, TO_VICT );
    act( "$n bites $N!", ch, NULL, victim, TO_NOTVICT );
    spell_poison( gsn_poison, ch->level, ch, victim );
    return TRUE;
}

bool spec_spider( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    CHAR_DATA *victim;

    if( ch->position != POS_FIGHTING
	|| !( victim = ch->fighting )
	|| number_percent( ) > 2 * ch->level )
	return FALSE;

    if( number_bits( 1 ) == 0 )
    {
	act( "You bite $N!", ch, NULL, victim, TO_CHAR );
	act( "$n bites you!", ch, NULL, victim, TO_VICT );
	act( "$n bites $N!", ch, NULL, victim, TO_NOTVICT );
	spell_poison( gsn_poison, ch->level, ch, victim );
    }
    else
    {
	act( "You spin a web around $N!", ch, NULL, victim, TO_CHAR );
	act( "$n spins a web around you!", ch, NULL, victim, TO_VICT );
	act( "$n spins a web around $N!", ch, NULL, victim, TO_NOTVICT );
	spell_web( gsn_web, ch->level, ch, victim );
    }
    return TRUE;
}



bool spec_thief( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    CHAR_DATA *victim;
    int gold;

    if( ch->position != POS_STANDING )
	return FALSE;

    for( victim = ch->in_room->people; victim;
	 victim = victim->next_in_room )
    {
	if( IS_NPC( victim )
	    || victim->level >= LEVEL_IMMORTAL
	    || number_bits( 3 ) != 0
	    || !can_see( ch, victim ) )	/* Thx Glop */
	    continue;

	/* Thanks to Zeke from MudX for pointing the percent bug */
	if( IS_AWAKE( victim ) && victim->level > 5
	    && can_see( victim, ch )
	    && number_percent( ) + victim->level - ch->level >= 33 )
	{
	    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 * number_range( 1, 20 ) / 100;
	    ch->gold += 3 * gold / 4;
	    victim->gold -= gold;
	    return TRUE;
	}
    }

    return FALSE;
}


/*
 * spec_thief with minor modifications
 * these will always be annoying little b******s
 */
bool spec_weevil( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    ROOM_INDEX_DATA *room;
    CHAR_DATA *victim;
    int gold;

    if( ch->position == POS_FIGHTING )
    {
	do_flee( ch, "" );
	return TRUE;
    }
    if( ch->position != POS_STANDING )
	return FALSE;

    for( victim = ch->in_room->people; victim;
	 victim = victim->next_in_room )
    {
	if( IS_NPC( victim )
	    || victim->level >= LEVEL_IMMORTAL
	    || number_bits( 3 ) != 0
	    || !can_see( ch, victim ) )	/* Thx Glop */
	    continue;

	if( IS_AWAKE( victim ) && victim->level > 5
	    && number_percent( ) < 33 && can_see( victim, ch ) )
	{
	    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 * number_range( 1, 20 ) / 100;
	    ch->gold += 3 * gold / 4;
	    victim->gold -= gold;
	    send_to_room( "You hear a chittering noise.", ch->in_room );
	    for( ;; )
	    {
		room = get_room_index( number_range( 100, 65536 ) );
		if( room && !IS_SET( room->room_flags, ROOM_NO_MOB )
		    && !IS_SET( room->room_flags, ROOM_SOLITARY ) )
		    break;
	    }
	    char_from_room( ch );
	    char_to_room( ch, room );
	    return TRUE;
	}
    }
    if( number_bits( 3 ) < 3 )
    {
	for( ;; )
	{
	    room = get_room_index( number_range( 100, 65536 ) );
	    if( room && !IS_SET( room->room_flags, ROOM_NO_MOB )
		&& !IS_SET( room->room_flags, ROOM_SOLITARY ) )
		break;
	}
	char_from_room( ch );
	char_to_room( ch, room );
	return TRUE;
    }

    return FALSE;
}


/*
 * Psionicist spec_fun by Thelonius for EnvyMud.
 */
bool spec_cast_psionicist( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    CHAR_DATA *victim;
    const char *spell;
    int sn;

    if( ch->position != POS_FIGHTING || IS_AFFECTED( ch, AFF_MIND_MIST )
	|| IS_AFFECTED( ch, AFF_MUTE )
	|| IS_SET( race_table[ch->race].race_abilities, RACE_MUTE )
	|| IS_SET( ch->in_room->room_flags, ROOM_CONE_OF_SILENCE ) )
	return FALSE;

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

    if( !victim )
	return FALSE;

    for( ;; )
    {
	int min_level;

	switch( number_bits( 4 ) )
	{
	case 0:
	    min_level = 0;
	    spell = "mind thrust";
	    break;
	case 1:
	    min_level = 4;
	    spell = "psychic drain";
	    break;
	case 2:
	    min_level = 6;
	    spell = "agitation";
	    break;
	case 3:
	    min_level = 8;
	    spell = "psychic crush";
	    break;
	case 4:
	    min_level = 9;
	    spell = "project force";
	    break;
	case 5:
	    min_level = 13;
	    spell = "ego whip";
	    break;
	case 6:
	    min_level = 14;
	    spell = "energy drain";
	    break;
	case 7:
	case 8:
	    min_level = 17;
	    spell = "psionic blast";
	    break;
	case 9:
	    min_level = 20;
	    spell = "detonate";
	    break;
	case 10:
	    min_level = 27;
	    spell = "disintegrate";
	    break;
	default:
	    min_level = 25;
	    spell = "ultrablast";
	    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 );
    return TRUE;
}


bool spec_cast_ghost( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    CHAR_DATA *victim;
    const char *spell;
    int sn;

    if( ch->in_room->area->plane->weather.sunlight != SUN_DARK )
    {

	if( !ch->in_room )
	{
	    bug( "Spec_cast_ghost: NULL in_room." );
	    return FALSE;
	}

	if( ch->fighting )
	    stop_fighting( ch, TRUE );

	act( "A beam of sunlight strikes $n, destroying $m.",
	    ch, NULL, NULL, TO_ROOM );

	extract_char( ch, TRUE );
	return TRUE;

    }

    if( ch->position != POS_FIGHTING
	|| IS_AFFECTED( ch, AFF_MUTE )
	|| IS_AFFECTED( ch, AFF_MIND_MIST )
	|| IS_SET( race_table[ch->race].race_abilities, RACE_MUTE )
	|| IS_SET( ch->in_room->room_flags, ROOM_CONE_OF_SILENCE ) )
	return FALSE;

    for( victim = ch->in_room->people; victim; victim = victim->next_in_room )
    {
	if( victim->deleted )
	    continue;
	if( victim->fighting == ch && can_see( ch, victim )
	    && number_bits( 2 ) == 0 )
	    break;
    }

    if( !victim )
	return FALSE;

    for( ;; )
    {
	int min_level;

	switch( number_bits( 4 ) )
	{
	case 0:
	    min_level = 0;
	    spell = "hex";
	    break;
	case 1:
	    min_level = 3;
	    spell = "weaken";
	    break;
	case 2:
	    min_level = 6;
	    spell = "freeze";
	    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;
	default:
	    min_level = 24;
	    spell = "gate";
	    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 );
    return TRUE;
}


/*
 * spec_fun to repair bashed doors by Thelonius for EnvyMud.
 */
bool spec_repairman( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    EXIT_DATA *pexit;
    EXIT_DATA *pexit_rev;
    ROOM_INDEX_DATA *to_room;
    int door;

    if( !IS_AWAKE( ch ) )
	return FALSE;

    door = number_range( 0, 5 );
    /*
     *	Could search through all doors randomly, but deathtraps would
     *	freeze the game!  And I'd prefer not to go through from 1 to 6...
     *	too boring.  Instead, just check one direction at a time.  There's
     *	a 51% chance they'll find the door within 4 tries anyway.
     *	-- Thelonius ( Monk )
     */
    if( !( pexit = ch->in_room->exit[door] ) )
	return FALSE;

    if( IS_SET( pexit->exit_info, EX_BASHED ) )
    {
	REMOVE_BIT( pexit->exit_info, EX_BASHED );
	act( "You repair the $d.", ch, NULL, pexit->keyword, TO_CHAR );
	act( "$n repairs the $d.", ch, NULL, pexit->keyword, TO_ROOM );

	/* Don't forget the other side! */
	if( ( to_room = pexit->to_room )
	    && ( pexit_rev = to_room->exit[rev_dir[door]] )
	    && pexit_rev->to_room == ch->in_room )
	{
	    CHAR_DATA *rch;

	    REMOVE_BIT( pexit_rev->exit_info, EX_BASHED );

	    for( rch = to_room->people; rch; rch = rch->next_in_room )
		act( "The $d is set back on its hinges.",
		    rch, NULL, pexit_rev->keyword, TO_CHAR );
	}

	return TRUE;
    }

    return FALSE;
}


bool spec_cast_god( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    CHAR_DATA *victim;
    const char *spell;
    int sn;

    if( ch->position != POS_FIGHTING
	|| IS_AFFECTED( ch, AFF_MUTE )
	|| IS_AFFECTED( ch, AFF_MIND_MIST )
	|| IS_SET( race_table[ch->race].race_abilities, RACE_MUTE )
	|| IS_SET( ch->in_room->room_flags, ROOM_CONE_OF_SILENCE ) )
	return FALSE;

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

    if( !victim )
	return FALSE;

    for( ;; )
    {
	int min_level;

	switch( number_bits( 5 ) )
	{
	case 0:	    min_level = 0;	    spell = "blindness";    break;
	case 1:	    min_level = 4;	    spell = "freeze";	    break;
	case 2:	    min_level = 7;	    spell = "weaken";	    break;
	case 3:	    min_level = 16;	    spell = "colour spray"; break;
	case 4:	    min_level = 24;	    spell = "energy drain"; break;
	case 7:	case 8:
	case 9:	    min_level = 30;	    spell = "fireball";	    break;
	case 10:    min_level = 32;	    spell = "fire breath";  break;
	case 11:    min_level = 32;	    spell = "frost breath"; break;
	case 12:    min_level = 32;	    spell = "lightning breath"; break;
	case 13:    min_level = 20;	    spell = "flamestrike";  break;
	case 14:    min_level = 20;	    spell = "dispel magic"; break;
	case 15:    min_level = 20;	    spell = "acid blast";   break;
	case 16:    min_level = 37;	    spell = "detonate";	    break;
	case 17:    min_level = 45;	    spell = "ultrablast";   break;
	case 18:    min_level = 90;	    spell = "disintegrate"; break;
	case 19:    min_level = 30;	    spell = "gas breath";   break;
	case 20:    min_level = 25;	    spell = "acid breath";  break;
	default:    min_level = 23;	    spell = "lightning bolt"; 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 );
    return TRUE;
}


bool spec_peacemaker( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    ROOM_INDEX_DATA *room;
    CHAR_DATA *victim;

    if( !IS_AWAKE( ch ) || ch->fighting
	|| IS_AFFECTED( ch, AFF_MUTE )
	|| IS_AFFECTED( ch, AFF_MIND_MIST )
	|| IS_SET( race_table[ch->race].race_abilities, RACE_MUTE )
	|| IS_SET( ch->in_room->room_flags, ROOM_CONE_OF_SILENCE ) )
	return FALSE;

    for( victim = ch->in_room->people; victim; victim = victim->next_in_room )
    {
	if( victim != ch && can_see( ch, victim ) && number_bits( 1 ) == 0 )
	    break;
    }

    if( !victim || IS_NPC( victim ) )
    {
	if( number_bits( 3 ) < 3 )
	{
	    do_say( ch, "I must keep the peace elsewhere." );
	    for( ;; )
	    {
		room = get_room_index( number_range( 100, 65536 ) );
		if( room && !IS_SET( room->room_flags, ROOM_NO_MOB )
		    && !IS_SET( room->room_flags, ROOM_SOLITARY ) )
		    break;
	    }
	    char_from_room( ch );
	    char_to_room( ch, room );
	    act( "$n has arrived on a mission of peace.",
		ch, NULL, NULL, TO_ROOM );
	    return TRUE;
	}
	return FALSE;
    }
    if( victim->fighting && number_bits( 1 ) == 0 )
    {
	do_say( ch, "There shall be no more fighting!" );
	mp_peace( ch, "" );
	return TRUE;
    }
    switch( number_bits( 3 ) )
    {
    default:
	for( ;; )
	{
	    room = get_room_index( number_range( 100, 65536 ) );
	    if( room && !IS_SET( room->room_flags, ROOM_NO_MOB )
		&& !IS_SET( room->room_flags, ROOM_SOLITARY ) )
		break;
	}
	act( "$n leaves on a mission of peace.", ch, NULL, NULL, TO_ROOM );
	send_to_char( "You leave to help someplace else.\n\r", ch );
	char_from_room( ch );
	char_to_room( ch, room );
	act( "$n has arrived on a mission of peace.", ch, NULL, NULL, TO_ROOM );
	return TRUE;

    case 0:
    case 1:
    case 2:
	act( "$n utters the word 'ecaep'.", ch, NULL, NULL, TO_ROOM );
	spell_armour( skill_lookup( "armour" ), ch->level, ch, victim );
	return TRUE;

    case 3:
    case 4:
	act( "$n utters the word 'ycrem'.", ch, NULL, NULL, TO_ROOM );
	spell_bless( skill_lookup( "bless" ), ch->level, ch, victim );
	return TRUE;

    case 5:
	act( "$n utters the words 'evol'.", ch, NULL, NULL, TO_ROOM );
	spell_endurance( skill_lookup( "endurance" ), ch->level, ch, victim );
	return TRUE;
    }
}



bool spec_deaf( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    char buf[MAX_INPUT_LENGTH];

    sprintf( buf, "%s, %s?",
	    ( number_bits( 1 ) == 0 ) ? "WATCHA SAY" : "COME AGAIN",
	    ( player->sex == SEX_MALE ) ? "SONNY"
	    : ( player->sex == SEX_FEMALE ) ? "LASS" : "MATE" );
    do_say( ch, buf );
    return TRUE;
}


bool spec_safe( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    do_say( ch, "You cannot hurt me weakling!" );
    do_say( ch, "I am protected from your puny attacks." );
    return TRUE;
}


bool spec_religion_recruit( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    char *argument = (char *)thing;
    char buf[MAX_INPUT_LENGTH];
    RELIGION_DATA * religion;

    if( str_infix( argument, "recruit me" )
	&& str_infix( argument, "would like to join" ) )
	return FALSE;

    one_argument( ch->name, buf );
    if( !( religion = religion_lookup( buf ) ) )
    {
	bug( "Invalid name for mob %d: %s",
		   ch->pIndexData->vnum, ch->name );
	return FALSE;
    }
    if( IS_NPC( player ) )
	return FALSE;
    if( player->pcdata->religion )
    {
	do_say( ch, "You cannot worship two masters." );
	return TRUE;
    }
    if( player->alignment < religion->align_min
	|| player->alignment > religion->align_max )
    {
	do_say( ch, "You are unsuitable for this religion." );
	return TRUE;
    }

    sprintf( buf, "So you want to join the %s religion, %s?",
	     religion->name, player->name );
    do_say( ch, buf );
    do_say( ch, "Very well, welcome to the joys of religion!" );
    player->pcdata->religion = religion;
    sprintf( buf, "%s has recruited %s to the %s religion.",
	     ch->short_descr, player->name, religion->name );
    wiznet( ch, WIZ_MISC, get_trust( player ), buf );
    return TRUE;
}


/* This function was written by Rox of Farside, Permission to
 * use is granted provided this header is retained
 */
bool spec_assassin( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    CHAR_DATA *victim;
    const char *mesg;

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

    for( victim = ch->in_room->people; victim; victim = victim->next_in_room )
    {
	/* this should kill mobs as well as players */
	if( victim->class != CLASS_THIEF
	    && get_first_class( victim ) != CLASS_THIEF
	    && get_second_class( victim ) != CLASS_THIEF )
	    break;
    }

    if( victim == NULL || victim == ch || IS_IMMORTAL( victim ) )
	return FALSE;
    if( victim->level > ch->level + 7 )
	return FALSE;

    switch( number_bits( 3 ) )
    {
    case 0:
	mesg = "Time to die...";			break;
    case 1:
	mesg = "Cabrone...";				break;
    case 2:
	mesg = "Welcome to your fate...";		break;
    case 3:
	mesg = "Ever dance with the devil...";		break;
    case 4:
	mesg = "On our turf eh...";			break;
    default:
	mesg = "Death to is the true end...";		break;
    }

    do_say( ch, mesg );
    multi_hit( ch, victim, gsn_backstab );
    return TRUE;
}


bool spec_drunk( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    CHAR_DATA *victim;

    if( !IS_AWAKE( ch ) || ch->fighting )
	return FALSE;

    for( victim = ch->in_room->people; victim; victim = victim->next_in_room )
    {
	if( victim != ch && can_see( ch, victim ) && number_bits( 1 ) == 0 )
	    break;
    }

    if( !victim || IS_NPC( victim ) )
	return FALSE;

    switch( number_bits( 4 ) )
    {
    default:
    case 0:
	act( "$n pukes", ch, NULL, NULL, TO_ROOM );
	return TRUE;

    case 1:
	act( "Oooohh noooo $n has begon to sing !!", ch, NULL, NULL, TO_ROOM );
	return TRUE;

    case 2:
	act( "$n sings 'Ole Ole Ole'.",	ch, NULL, NULL, TO_ROOM );
	return TRUE;

    case 3:
	act( "*hic*", ch, NULL, NULL, TO_ROOM );
	return TRUE;

    case 4:
	act( "$n hiccups",  ch, NULL, NULL, TO_ROOM );
	return TRUE;

    case 5:
	act( "$n tries to hit $N but falls to the ground.", ch, NULL, victim, TO_ROOM );
	return TRUE;

    case 6:
    case 7:
	act( "$n burps", ch, NULL, NULL, TO_ROOM );
	return TRUE;

    case 8:
	act( "$n orders another bottle of beer.", ch, NULL, NULL, TO_ROOM );
	return TRUE;

    case 9:
	do_say( ch, "Ohh i feel so sick..." );
	return TRUE;

    case 10:
	do_yell( ch, "I'm so drunk I'm sober" );
	return TRUE;

    case 11:
	do_say( ch, "En we gaan nog niet naar huis..." );
	return TRUE;

    case 12:
	act( "$n pukes all over $N.", ch, NULL, victim, TO_ROOM );
	return TRUE;

    case 13:
	do_say( ch, "If you want a drink..." );
	do_say( ch, "You'll need to order one... Hahaha" );
	return TRUE;

    case 14:
	do_say( ch, "Hey guys... buy me a beer will you...*hic*" );
	return TRUE;

    case 15:
	do_say( ch, "Hey you bar-dude gimme another beer will ya" );
	return TRUE;
    }
}


/*
 * Admin note: since a necro mob is NASTY, make it a rare mob that has
 * this spec.
 * Be aware of the player corpse looting technique offered by a naromantic
 * mob:
 *    Player dies.
 *    Evil player takes his necromancer charmie to the corpse.
 *    Corpse gets animated and Mr. Evil slays the zombie and grabs the
 *    stuff, disappears into the sunset in his hog...
 * --Symposium
 */
bool spec_necro( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    OBJ_DATA *obj;
    OBJ_DATA *corpse = NULL;
    int count = 0;

    for( obj = ch->in_room->contents; obj; obj = obj->next_content )
    {
	if( !obj->deleted
	    && ( obj->item_type == ITEM_CORPSE_NPC
	      || obj->item_type == ITEM_CORPSE_PC )
	    && number_range( 0, count++ ) == 0 )
	    corpse = obj;
    }
    if( !corpse )
	return FALSE;
    animate_corpse( ch, corpse, -1, -1 );
    return TRUE;
}


/*
 * Admin note: changeling mobiles are supposed to be extremely difficult
 * to kill, or at least quite tricky.  So that players cannot abuse the
 * changelings by having low level characters sit at them until they get
 * very low stats, make every changeling aggressive.
 * --Symposium
 */
bool spec_changeling( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    CHAR_DATA *victim;
    char buf[ MAX_STRING_LENGTH ];

    for( victim = ch->in_room->people; victim; victim = victim->next_in_room )
    {
	if( can_see( ch, victim ) && number_bits( 2 ) == 0 )
	    break;
    }

    if( !victim || IS_NPC( victim ) || IS_IMMORTAL( victim ) )
	return FALSE;

    act( "$n slowly morphs into a perfect semblance of $N.",
	 ch, NULL, victim, TO_ALL );

    sprintf( buf, "%s %s", ch->name, victim->name );
    free_string( ch->name );
    ch->name = str_dup( buf );
    free_string( ch->short_descr );
    if( victim->short_descr && victim->short_descr[0] != '\0' )
	ch->short_descr = str_dup( victim->short_descr );
    else
	ch->short_descr = str_dup( victim->name );


    /* Everything that can be changed to match the victim is
     * however we should do little about hitpoints etc
     * as the changeling may have been hurt already and
     * mobile hitpoints are good enough.
     */
    ch->sex = victim->sex;
    ch->class = victim->class;
    ch->race = victim->race;
    ch->hitroll = victim->hitroll;
    ch->damroll = victim->damroll;
    ch->speed = victim->speed;
    ch->armour = victim->armour;
    ch->body_parts = victim->body_parts;
    ch->damaged_parts = victim->damaged_parts;
    ch->spec_fun = 0;
    return TRUE;
}


bool death_explode( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    CHAR_DATA *victim, *victim_next;

    act( "$n reaches down to $s belt and presses a button.", ch, NULL, NULL, TO_ROOM );
    ch->position = POS_STANDING;
    do_say( ch, "HAH! You wont take me alive!" );
    act( "$n explodes violently!", ch, NULL, NULL, TO_ROOM );

    for( victim = ch->in_room->people; victim; victim = victim_next )
    {
	victim_next = victim->next_in_room;
	if( victim->deleted || victim == ch )
	    continue;

	( *skill_table[gsn_explosive].spell_fun )
	    ( gsn_explosive, ch->level, ch, ( void * )victim );
    }
    return FALSE;		/* no corpse made here */
}



bool death_ghost( CHAR_DATA *ch, CHAR_DATA *player, int type, void *thing )
{
    OBJ_DATA *obj, *obj_next;

    act( "$n screams then swiftly dissipates.", ch, NULL, NULL, TO_ROOM );
    for( obj = ch->carrying; obj; obj = obj_next )
    {
	obj_next = obj->next_content;
	if( obj->deleted )
	    continue;
	obj_from_char( obj );
	obj_to_room( obj, ch->in_room );
    }
    return TRUE;
}