dawn/notes/
dawn/src/
dawn/src/docs/
/**************************************************************************/
// magic_ke.cpp - spells/skills written by Kerenos
/***************************************************************************
 * 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 the dawn license *
 *    in licenses.txt... In particular, you may not remove this copyright  *
 *    notice.                                                              *
 **************************************************************************/
#include "include.h"
#include "areas.h"
#include "magic.h"
#include "o_lookup.h"
#include "ictime.h"


/********************************/
/* START OF FUNCTION PROTOTYPES */
bool check_social( char_data *ch, char *arg, char *arg1, bool global );
/*  END OF FUNCTION PROTOTYPES  */
/********************************/


/**************************************************************************/
// Kerenos - Sept 98
SPRESULT spell_otterlungs( int sn, int level, char_data *ch, void *, int )
{
	AFFECT_DATA		af;

// You may want to omit this check
// Would allow character to update his otterlungs

	if ( is_affected( ch, sn )) {
		ch->println( "You already are affected by otterlungs." );
		return HALF_MANA;
	}

	af.where		= WHERE_AFFECTS;
	af.type			= sn;
	af.level		= ch->level;
	af.duration		= level;
	af.location		= APPLY_NONE;
	af.modifier		= 0;
	af.bitvector	= AFF_OTTERLUNGS;
					
	affect_to_char( ch, &af );

	ch->println("You can now travel underwater without fear of drowning.");

	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_benedict( int sn, int level, char_data *ch, void *vo, int )
{
	char_data		*victim;
	AFFECT_DATA		af;
	int			chance, stat;

	victim = ( char_data * ) vo;

	if ( victim == ch ) {
		ch->println( "You may only benedict others, it is a selfless supplication." );
		return NO_MANA;
	}

	if ( !IS_IMMORTAL( ch )) {
		if ( victim->alliance!= URANGE(ch->alliance -1, victim->alliance, ch->alliance+1)) { 
			act( "You cannot grant a benediction upon $N.", ch, NULL, victim, TO_CHAR );
			return HALF_MANA;
		}	// Only works on PC's with simular alignment, (good neutral evil)
	}		// lawful and chaotic makes no difference	

	if ( is_affected( victim, sn )) {
		act( "The grace of the gods already touch $N.", ch, NULL, victim, TO_CHAR );
		return HALF_MANA;
	}

	if (( chance = number_range( 0, 1 ))){
		stat = number_range( 1, 5 );	// ST QU PR EM IN
	}else{
		stat = number_range( 26, 30);	// CO AG SD ME RE
	}

	af.where		= WHERE_AFFECTS;
	af.type			= sn;
	af.level		= level;
	af.duration		= 24;
	af.location		= translate_old_apply_number(stat);	// determined above 
	af.modifier		= 10;				// level dependant or always +10?  Balance issue
	af.bitvector	= 0;				// will be a fairly low level spell so I think
										// leaving it at 10 will be ok.
	affect_to_char( victim, &af );

	victim->println( "The gods smile kindly upon you." );
	act( "The gods smile kindly upon $N.", ch, NULL, victim, TO_CHAR );

	return FULL_MANA;
}

/***********************************************************************/
SPRESULT spell_maledict( int sn, int level, char_data *ch, void *vo, int )
{
	char_data		*victim;
	AFFECT_DATA		af;
	int				chance, stat;

	victim = ( char_data * ) vo;

	if ( victim == ch ) {
		ch->println( "Your god will not forsake you." );
		return NO_MANA;
	}

	if ( !IS_IMMORTAL( ch )) {
		if ( victim->alliance== URANGE(ch->alliance -1, victim->alliance, ch->alliance+1)) { 
			act( "You cannot maledict $N.", ch, NULL, victim, TO_CHAR );
			return HALF_MANA;
		}	// Only works on PC's of unequal alignment, (good neutral evil)
	}		// lawful and chaotic makes no difference

	if ( is_affected( victim, sn )) {
		act( "The cannot maledict $N any further.", ch, NULL, victim, TO_CHAR );
		return HALF_MANA;
	}

	if (( chance = number_range( 0, 1 ))){
		stat = number_range( 1, 5 );	// ST QU PR EM IN
	}else{
		stat = number_range( 26, 30);	// CO AG SD ME RE
	}

	af.where		= WHERE_AFFECTS;
	af.type			= sn;
	af.level		= level;
	af.duration		= 24;
	af.location		= translate_old_apply_number(stat);	// determined above 
	af.modifier		= -10;				// level dependant or always -10?  Balance issue
	af.bitvector	= 0;				// will be a fairly low level spell so I think
										// leaving it at -10 will be ok.
	affect_to_char( victim, &af );

	victim->println( "The gods look upon you with distate." );

	act( "The gods look upon $N with distate.", ch, NULL, victim, TO_CHAR );

	return FULL_MANA;
}

/****************************************************************************/
SPRESULT spell_earthwalk( int sn, int level, char_data *ch, void *vo,int )
{
	char_data	*victim		= ( char_data * ) vo;
	char		*buf;

	if (( victim = get_char_icworld( ch, target_name )) == NULL
	 ||   victim == ch
	 ||   victim->in_room == NULL
	 ||   !can_see_room(ch,victim->in_room )
	 ||   IS_SET( victim->in_room->room_flags, ROOM_SAFE )
	 ||	  IS_SET( victim->in_room->room_flags, ROOM_INDOORS )
	 ||	  IS_SET( victim->in_room->room_flags, ROOM_ANTIMAGIC )
	 ||	  IS_SET( victim->in_room->room_flags, ROOM_PET_SHOP )
	 ||   IS_SET( victim->in_room->room_flags, ROOM_PRIVATE )
	 ||   IS_SET( victim->in_room->room_flags, ROOM_SOLITARY )
	 ||   IS_SET( victim->in_room->room_flags, ROOM_NO_RECALL )
	 ||   IS_SET( victim->in_room->room_flags, ROOM_NOSCRY )
	 ||   IS_SET( victim->in_room->area->area_flags, AREA_NOSCRY )
	 ||   IS_SET( victim->in_room->area->area_flags, AREA_NOGATEINTO)
	 ||   IS_SET( ch->in_room->room_flags, ROOM_NO_RECALL )
	 ||   victim->level >= level + 3
	 ||	  victim->in_room->sector_type == SECT_INSIDE 
 	 ||	  victim->in_room->sector_type == SECT_CITY 
	 ||	  victim->in_room->sector_type == SECT_WATER_SWIM 
	 ||	  victim->in_room->sector_type == SECT_WATER_NOSWIM 
	 ||	  victim->in_room->sector_type == SECT_AIR 
	 ||	  victim->in_room->sector_type == SECT_UNDERWATER 
	 ||   ( !IS_NPC(victim) && victim->level >= LEVEL_IMMORTAL )		// NOT trust
	 ||   ( IS_NPC(victim) && IS_SET(victim->imm_flags,IMM_SUMMON ))
	 ||   ( IS_NPC(victim) && saves_spell( level, victim,DAMTYPE(sn)))
	 ||   ( !IS_NPC(victim) && saves_spell( level, victim, DAMTYPE(sn)))) {
		  ch->println( "You failed." );
		return FULL_MANA;
	}

	switch ( ch->in_room->sector_type ) {
		case SECT_FIELD:
			act("The grass below $n opens up and swallows $m up.",ch,NULL,NULL,TO_ROOM);
			ch->println( "The grass below you opens wide and swallows you." );
			break;
		case SECT_FOREST:
			act("$n melts into a tree and vanishes.",ch,NULL,NULL,TO_ROOM);
			ch->println( "You step into a tree and vanish." );
			break;
		case SECT_HILLS:
		case SECT_MOUNTAIN:
			act("$n suddenly sinks into the rocky soil and is gone.",ch,NULL,NULL,TO_ROOM);
			ch->println( "Suddenly the rocky soil splits open and you sink down." );
			break;
		case SECT_SWAMP:
			act("The swampy ground under $n bubbles, and $e sinks and is gone.",ch,NULL,NULL,TO_ROOM);
			ch->println( "The ground under your feet swallows you up." );
			break;
		case SECT_DESERT:
			act("A sandy whirlpool is created under $n and suddenly $e disappears.",ch,NULL,NULL,TO_ROOM);
			ch->println( "You flush yourself into the sand and vanish." );
			break;
		case SECT_CAVE:
			act("$n is sucked into the ground and is longer before you.",ch,NULL,NULL,TO_ROOM);
			ch->println( "The ground sucks you deep into the bowels of the earth." );
			break;
		default:
			ch->println( "You could not attune yourself enough to travel." );
			return HALF_MANA;
			break;
	}
	
	char_from_room(ch);
	char_to_room(ch,victim->in_room);

	switch ( ch->in_room->sector_type ) {
		case SECT_FIELD:
			buf = str_dup("rises from the grass");
			break;
		case SECT_FOREST:
			buf = str_dup("steps out of a tree");
			break;
		case SECT_HILLS:
		case SECT_MOUNTAIN:
			buf = str_dup("rises up from the rocky soil");
			break;
		case SECT_SWAMP:
			buf = str_dup("rises up from the swampy ground");
			break;
		case SECT_DESERT:
			buf = str_dup("materializes from the sand");
			break;
		case SECT_CAVE:
			buf = str_dup("appears from the ground");
			break;
		default:
			buf = str_dup("appears from nowhere");		// This should never occur
			break;
	}
			
	act("$n $t.",ch,buf,NULL,TO_ROOM);
	do_look(ch,"auto");

    if ( IS_NPC( ch ) && HAS_TRIGGER( ch, TRIG_ENTRY ))
		mp_percent_trigger( ch, NULL, NULL, NULL, TRIG_ENTRY );

    if ( !IS_NPC( ch ))
		mp_greet_trigger( ch );

    return FULL_MANA;
}

/*******************************************************************************/
SPRESULT spell_detect_scry( int sn, int level, char_data *ch, void *, int )
{
	AFFECT_DATA		af;

	if ( is_affected( ch, sn )) {
		ch->println( "You can already detect scrying attempts." );
		return HALF_MANA;
	}

	af.where		= WHERE_AFFECTS;
	af.type			= sn;
	af.level		= level;
	af.duration		= 24;
	af.location		= APPLY_NONE;
	af.modifier		= 0;
	af.bitvector	= 0;
						
	affect_to_char( ch, &af );

	ch->printf( "You are now able to detect scrying attempts." );

	return FULL_MANA;
}

/*****************************************************************************/
SPRESULT spell_sunfire( int sn, int level, char_data *ch, void *vo, int )
{
	char_data		*victim = (char_data *) vo;
	int				dam, dam2;

	dam2 = number_range( 6, 12);
	dam  = dice( level, dam2 );

	if ( !IS_OUTSIDE( ch )
		|| ( time_info.hour < 6 || time_info.hour > 18 )) {
		ch->println( "This spell requires the light of the sun to work." );
		return NO_MANA;
	}

	if ( ch->in_room->sector_type == SECT_CAVE )
	{
		ch->println( "The sun does not shine here." );
		return NO_MANA;
	}

	if ( saves_spell( level, victim, DAMTYPE(sn)))
		dam /= 2;
	damage_spell( ch, victim, dam, sn, DAMTYPE(sn), true );
	return FULL_MANA;
}

/********************************************************************************/
SPRESULT spell_cure_chaotic_poison(int ,int level,char_data *ch,void *vo,int )
{
	char_data *victim = (char_data *) vo;

	if ( !is_affected( victim, gsn_chaotic_poison ))
	{
		if (victim == ch)
			ch->println( "You aren't poisoned." );
		else
			act("$N doesn't appear to be poisoned.",ch,NULL,victim,TO_CHAR);
		return HALF_MANA;
	}
 
	if (check_dispel(level,victim,gsn_chaotic_poison ))
	{
		victim->println( "The poison no longer courses through your veins!" );
		act("$n is no longer poisoned.",victim,NULL,NULL,TO_ROOM);
	}
	else
		ch->println( "Spell failed." );

	return FULL_MANA;
}

/****************************************************************************/
SPRESULT spell_shadowflight( int , int level, char_data *ch, void *vo,int )
{
	char_data	*victim		= ( char_data * ) vo;

	if ( time_info.hour >= 6 && time_info.hour <= 18 ) {
		ch->println( "You may only use shadowflight under the cloak of night." );
		return HALF_MANA;
	}

	if (( victim = get_char_icworld( ch, target_name )) == NULL
	 ||   victim == ch
	 ||   victim->in_room == NULL
	 ||   !can_see_room(ch,victim->in_room )
	 ||   IS_SET( victim->in_room->room_flags, ROOM_SAFE )
	 ||	  IS_SET( victim->in_room->room_flags, ROOM_INDOORS )
	 ||	  IS_SET( victim->in_room->room_flags, ROOM_ANTIMAGIC )
	 ||	  IS_SET( victim->in_room->room_flags, ROOM_PET_SHOP )
	 ||   IS_SET( victim->in_room->room_flags, ROOM_PRIVATE )
	 ||   IS_SET( victim->in_room->room_flags, ROOM_SOLITARY )
	 ||   IS_SET( victim->in_room->room_flags, ROOM_NO_RECALL )
	 ||   IS_SET( victim->in_room->room_flags, ROOM_NOSCRY )
	 ||   IS_SET( victim->in_room->area->area_flags, AREA_NOSCRY )
	 ||   IS_SET( victim->in_room->area->area_flags, AREA_NOGATEINTO )	 
	 ||   IS_SET( ch->in_room->room_flags, ROOM_NO_RECALL )
	 ||   victim->level >= level + 5
	 ||   ( !IS_NPC(victim) && victim->level >= LEVEL_IMMORTAL )		// NOT trust
	 ||   ( IS_NPC(victim) && IS_SET(victim->imm_flags,IMM_SUMMON ))) {
		  ch->println( "You failed." );
		return FULL_MANA;
	}

	if ( ch->in_room->area->continent != victim->in_room->area->continent )
	{
		ch->println( "The spell cannot span such a great distance." );
		return FULL_MANA;
	}


	act("$n steps into the night and vanishes.",ch,NULL,NULL,TO_ROOM);
	ch->println( "You step into the night and vanish." );
	char_from_room(ch);
	char_to_room(ch,victim->in_room);

	act("The shadows suddenly deepen.",ch,NULL,NULL,TO_ROOM);
	do_look(ch,"auto");

    if ( IS_NPC( ch ) && HAS_TRIGGER( ch, TRIG_ENTRY ))
		mp_percent_trigger( ch, NULL, NULL, NULL, TRIG_ENTRY );

    if ( !IS_NPC( ch ))
		mp_greet_trigger( ch );

    return FULL_MANA;
}

/*******************************************************************************/
SPRESULT spell_mirage(int,int,char_data *ch,void *,int )
{
	ch->mirage = ch->in_room->vnum;
	ch->mirage_hours = UMAX( 1, number_range( ch->level/4, ch->level/2));
	ch->println( "You have attuned your image to this location." );
	return FULL_MANA;
}
/*******************************************************************************/
SPRESULT spell_commune_with_dead(int, int, char_data *ch,void *vo,int target)
{
	OBJ_DATA *corpse;

	if (target == TARGET_OBJ)
	{
		corpse = (OBJ_DATA *) vo;

		if (corpse->item_type != ITEM_CORPSE_NPC 
			&& corpse->item_type != ITEM_CORPSE_PC)
		{
			ch->println( "You can only commune through corpses." );
			return HALF_MANA;
		}
		act( "A ghostly form rises from $p.", ch, corpse, NULL, TO_CHAR );
		if(corpse->killer){
			ch->wraplnf("A mental image forms in your mind, you see the outline of %s.",
				corpse->killer );
		}else{
			ch->wrapln( "A mental image starts to form in your mind, "
				"then vanishes before you can focus on it.");
		}

		return FULL_MANA;
	}

	ch->println( "You can only commune through corpses." );
	return HALF_MANA;
}
/*******************************************************************************/
SPRESULT spell_utterdark( int sn, int level, char_data *ch, void *, int )
{
	AFFECT_DATA		af;

	if ( IS_SET( ch->in_room->room_flags, ROOM_LAW ))
	{
		ch->println( "Spell failed." );
		return NO_MANA;
	}

	if ( IS_SET( ch->in_room->affected_by, ROOMAFF_UTTERDARK )) {
		ch->println( "This room is already as dark as it will get." );
		return HALF_MANA;
	}

	if (IS_SET(ch->in_room->room_flags,ROOM_LAW))
	{
		ch->println( "For a moment the room appears dark, then the darkness dissipates as quickly as it came." );
		act( "For a moment the room appears dark, then the darkness dissipates as quickly as it came.", ch, NULL, NULL, TO_ROOM );
		return HALF_MANA;
	}


	af.where		= WHERE_AFFECTS;
	af.type			= sn;
	af.level		= ch->level;
	af.duration		= level/20;
	af.location		= APPLY_NONE;
	af.modifier		= 0;
	af.bitvector	= ROOMAFF_UTTERDARK;
						
	affect_to_room( ch->in_room, &af );

	ch->println( "Suddenly, everything around you becomes very dark." );
	act( "Suddenly, everything around you becomes very dark.", ch, NULL, NULL, TO_ROOM );
	return FULL_MANA;
}
/*******************************************************************************/
SPRESULT spell_alarm( int sn, int, char_data *ch, void *, int )
{
	AFFECT_DATA		af;

	if(!ch->in_room){
		bug("spell_alarm(): ch->in_room==NULL.");
		return NO_MANA;
	}

	// This should never happen, since entering a room with alarm
	// should trip the alarm off
	if ( IS_SET( ch->in_room->affected_by, ROOMAFF_ALARM )) {
		ch->println( "This room is already alarmed." );
		return NO_MANA;
	}

	if ( is_affected( ch, sn )) {
		ch->println( "You cannot place another alarm quite yet." );
		return NO_MANA;
	}

	af.where		= WHERE_AFFECTS;
	af.type			= sn;
	af.level		= ch->level;
	af.duration		= -1;			// Permanent
	af.location		= APPLY_NONE;
	af.modifier		= 0;
	af.bitvector	= ROOMAFF_ALARM;
						
	affect_to_room( ch->in_room, &af );
	ch->in_room->alarm = ch;
	ch->println( "The alarm has been set." );

	af.where		= WHERE_AFFECTS;
	af.type			= sn;
	af.level		= ch->level;
	af.duration		= 24;			
	af.location		= APPLY_NONE;
	af.modifier		= 0;
	af.bitvector	= 0;
	affect_to_char( ch, &af );

	return FULL_MANA;
}
/*******************************************************************************/
SPRESULT spell_divine_light( int sn, int level, char_data *ch, void *, int )
{
	OBJ_DATA	*dlight;
	AFFECT_DATA	af;

	if ( is_affected( ch, sn )) {
		ch->println( "You cannot summon the mists quite yet." );
		return NO_MANA;
	}

	if ( get_obj_index( OBJ_VNUM_DIVINE_LIGHT ) == NULL )
	{
		bugf("Vnum %d not found for Divine Light!", OBJ_VNUM_DIVINE_LIGHT );
		ch->printlnf( "Vnum %d not found for Divine Light, please report to the admin.", OBJ_VNUM_DIVINE_LIGHT );
		return NO_MANA;
	}

	dlight = create_object( get_obj_index( OBJ_VNUM_DIVINE_LIGHT ));
	dlight->timer = 25;
	dlight->value[3] = (100 + ((level / 10) * 5));	// Heal bonus of 5% per 10 levels
	dlight->value[4] = (100 + ((level / 20) * 5));	// Mana bonus of 5% per 20 levels
	obj_to_room( dlight, ch->in_room );

	act( "$n calls up to the heavens and a shimmering globe of light descends,", ch, NULL, NULL, TO_ROOM );
	act( "diffusing into an ethereal, glowing mist that hovers on the floor.", ch, NULL, NULL, TO_ROOM );
	act( "You call up to the heavens and a shimmering globe of light descends,", ch, NULL, NULL, TO_CHAR );
	act( "diffusing into an ethereal, glowing mist that hovers on the floor.", ch, NULL, NULL, TO_CHAR );

	af.where		= WHERE_AFFECTS;
	af.type			= sn;
	af.level		= ch->level;
	af.duration		= 24;			
	af.location		= APPLY_NONE;
	af.modifier		= 0;
	af.bitvector	= 0;
	affect_to_char( ch, &af );

	return FULL_MANA;
}

/*******************************************************************************/
SPRESULT spell_immolation( int sn, int level, char_data *ch, void *, int )
{
	char_data *vch;
	AFFECT_DATA af;

	if ( is_affected( ch, gsn_immolation )) {
		ch->println( "You failed." );
		return NO_MANA;
	}

	ch->println( "You are engulfed within the flames of wizardry." );
	act( "$n is engulfed in fire.", ch, NULL, NULL, TO_ROOM );

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level	 = level;
	af.duration  = 2;
	af.location  = APPLY_HITROLL;
	af.modifier  = get_skill(ch, gsn_sorcery ) / 5;
	af.bitvector = 0;
	affect_to_char( ch, &af );

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level	 = level;
	af.duration  = 2;
	af.location  = APPLY_DAMROLL;
	af.modifier  = get_skill(ch, gsn_sorcery ) / 5;
	af.bitvector = 0;
	affect_to_char( ch, &af );

	af.where     = WHERE_AFFECTS;
	af.type      = sn;
	af.level	 = level;
	af.duration  = 2;
	af.location  = APPLY_AC;
	af.modifier  = 0 - get_skill(ch, gsn_sorcery ) / 2;
	af.bitvector = 0;
	affect_to_char( ch, &af );


	ch->println( "Tongues of flame from your body fly forth." );
	act( "Fire from $n reach out threatening to consume you.", ch, NULL, NULL, TO_ROOM );

    for ( vch = ch->in_room->people; vch; vch = vch->next_in_room )
	{
		if ( vch->in_room == NULL )
			continue;
		if ( vch->in_room == ch->in_room )
		{
			if ( vch != ch && !is_safe_spell(ch,vch,true))
			if (IS_AFFECTED(vch,AFF_FLYING))
				damage_spell(ch,vch,0,sn,DAMTYPE(sn),true);
			else
				damage_spell( ch,vch, dice(level, 10 ) + 10, sn, DAMTYPE(sn),true);
			continue;
		}
	}
	return FULL_MANA;
}

/*******************************************************************************/
SPRESULT spell_treeform( int sn, int level, char_data *ch, void *, int )
{
	AFFECT_DATA af;

	if ( ch->in_room->sector_type != SECT_FOREST )
	{
		ch->println( "You can only cast this spell in a forest." );
		return NO_MANA;
	}

	if ( IS_SET( ch->affected_by2, AFF2_TREEFORM ))
	{
		ch->println( "You have already assumed the shape of a tree." );
		return NO_MANA;
	}

	if ( !is_affected( ch, gsn_barkskin ))
	{
		ch->println( "You must make your skin as that of a tree first." );
		return NO_MANA;
	}

	af.where     = WHERE_AFFECTS2;
	af.type      = sn;
	af.level	 = level;
	af.duration  = 24;
	af.location  = APPLY_NONE;
	af.modifier  = 0;
	af.bitvector = AFF2_TREEFORM;
	affect_to_char( ch, &af );

	ch->println( "Your body transforms into the shape of a tree." );
	return FULL_MANA;

}

/*******************************************************************************/
SPRESULT spell_pass_without_trace( int sn, int level, char_data *ch, void *, int )
{
	AFFECT_DATA af;

	if (IS_AFFECTED2(ch, AFF2_PASSWOTRACE))
	{
		ch->println("You are not leaving any footprints already.");
		return NO_MANA;
	}

	af.where	= WHERE_AFFECTS2;
	af.type		= sn;
	af.level	= level;
	af.duration = 24;
	af.location	= APPLY_NONE;
	af.modifier = 0;
	af.bitvector= AFF2_PASSWOTRACE;
	affect_to_char( ch, &af );

	ch->println( "You will not leave footprints outdoors." );
	return FULL_MANA;
}

/*******************************************************************************/
SPRESULT spell_pine_needles( int sn, int level, char_data *ch, void *, int )
{
	AFFECT_DATA af;

	if ( ch->in_room->sector_type != SECT_FOREST )
	{
		ch->println( "You can only cast this spell in a forest." );
		return NO_MANA;
	}

	if ( is_affected( ch, sn ))
	{
		ch->println( "Pine needles already swirl about you." );
		return HALF_MANA;
	}

	af.where		= WHERE_AFFECTS;
	af.type			= sn;
	af.level		= level;
	af.duration		= 24;
	af.modifier		= -(level / 5 + 1);	// -2 to -20
	af.location		= APPLY_AC;
	af.bitvector	= 0;
	affect_to_char( ch, &af );

	ch->println( "A swirl of pine needles surrounds you." );
	act( "A swirl of pine needles surrounds $n.", ch, NULL, NULL, TO_ROOM );
	return FULL_MANA;
}

/*******************************************************************************/
void do_needlepoint( char_data *ch, char *argument )
{
	int				ac;		// to store the -ac value to be ++ed
	AFFECT_DATA		paf;
	char_data		*victim = NULL;
	char			arg1[MIL];
	char			arg2[MIL];

	if ( !is_affected( ch, gsn_pine_needles )){
		ch->println("You have to be affected by pine needles to use this spell.");
		return;
	}

	argument = one_argument( argument, arg1 );
	argument = one_argument( argument, arg2 );

	if ( IS_NULLSTR( arg1 ))
	{
		victim = ch->fighting;
		if (victim == NULL)
		{
			ch->println( "But you aren't fighting anyone!" );
			return;
		}
	} 
	else if (( victim = get_char_room( ch, arg1 )) == NULL )
	{
		ch->println( "They aren't here." );
		return;
	}

	if ( !can_initiate_combat( ch, victim, CIT_GENERAL )) return;

	// point to the right affect in ch->affected
	paf = *affect_find( ch->affected, gsn_pine_needles );

	// store the ac from the pine needles into int ac
	ac = paf.modifier;

	if ( ch->desc && ch->desc->repeat>4 )
	{
		ac += 5;				// spamming point will weaken the needles by 5 :)
		ch->wrapln( "The constant stream of needles issuing forth causes some of the other needles to drop harmlessly to the ground." );
	}

	if ( ac >= 0 )
	{
		ch->println( "You have depleted all your pine needles." );
		affect_strip( ch, gsn_pine_needles );
		return;
	}

	// increment ac, lessening their reserve by one (or all if 10 or more and all is used)
	if ( !str_cmp( arg2, "all" ))
	{
		if ( ac > -10 )
		{
			ch->println( "You don't have enough needles swirling about you to do this." );
			return;
		}
		else
		{ // all of them shoot (acid blast damage)
			act( "You shoot a barrage of pine needles at $N.", ch, NULL, victim, TO_CHAR );
			act( "$n let's loose a barrage of needles at $N.", ch, NULL, victim, TO_ROOM );
			if ( ac <= -20 ) {
				damage_spell( ch, victim, ( dice( ch->level, 10 )) * 2, gsn_pine_needles, DAM_PIERCE, true );
				ch->mana -= 75;
			}
			else
			{
				damage_spell( ch, victim, ( dice( ch->level, 10 )) , gsn_pine_needles, DAM_PIERCE, true );
				ch->mana -= 30;
			}
			ch->println( "You have depleted all your pine needles." );
			affect_strip( ch, gsn_pine_needles );
			WAIT_STATE(ch, skill_table[gsn_pine_needles].beats * 3 / 2);
			return;
		}
	}
	
	act( "One of your pine needles flies towards $N.", ch, NULL, victim, TO_CHAR );
	act( "A needle from $n flies straight towards you.", ch, NULL, victim, TO_VICT );
	act( "A needle from $n flies towards $N.", ch, NULL, victim, TO_NOTVICT );
	damage_spell( ch, victim, ch->level / 4 + 2, gsn_pine_needles, DAM_PIERCE, true );
	ch->mana -= 5;
	WAIT_STATE(ch, skill_table[gsn_pine_needles].beats );

	// increment and update AC in character's thingie :)
	ac++;

	affect_strip( ch, gsn_pine_needles );

	paf.where		= WHERE_AFFECTS;
	paf.type		= gsn_pine_needles;
	paf.level		= ch->level;
	paf.duration	= 24;
	paf.modifier	= ac;
	paf.location	= APPLY_AC;
	paf.bitvector	= 0;
	affect_to_char( ch, &paf );

	return;
}

/*******************************************************************************/
SPRESULT spell_spirit_hammer(int sn, int, char_data *ch, void *, int )
{
	AFFECT_DATA af;
	OBJ_INDEX_DATA *pObj;
	OBJ_DATA *obj;
	OBJ_DATA *cObj;
	int numdie, dietype, random, vlevel;

	if ( is_affected( ch, gsn_spirit_hammer ))
	{
		ch->println("You cannot summon another hammer quite yet.");
		return NO_MANA;
	}

	if (( pObj = get_obj_index( OBJ_VNUM_SPIRIT_HAMMER )) == NULL )
	{
		ch->printf( "Vnum %d not found for Spirit Hammer, please report to the admin.", OBJ_VNUM_SPIRIT_HAMMER );
		return NO_MANA;
	}

	obj = create_object( pObj);
	obj->level = ch->level;

	vlevel	   = obj->level + number_range( 0, (( 100 - ch->level ) / 10 ));
	// first try to get a random damage based on level
	random  = number_range( 0, 7 );
	numdie  = weapon_balance_lookup( vlevel, random, 0 );
	dietype = weapon_balance_lookup( vlevel, random, 1 );	

	// damage lookup failed, use polarmost damage class,
	if ( numdie == 0 ||  dietype == 0 )
	{
		numdie  = weapon_balance_lookup( vlevel, 0, 0 );
		dietype = weapon_balance_lookup( vlevel, 0, 1 );
	}


	obj->attune_flags = ATTUNE_NEED_TO_USE|ATTUNE_HARD|ATTUNE_INFURIATING|ATTUNE_PREVIOUS;
	obj->attune_id    = ch->id;
	obj->timer        = 48;
	obj->value[1]	  = numdie;
	obj->value[2]	  = dietype;
	obj->wear_loc	  = WEAR_WIELD;

	if ( IS_EVIL( ch )){
		SET_BIT( obj->extra_flags, OBJEXTRA_ANTI_GOOD );
	}

	if ( IS_GOOD( ch )){
		SET_BIT( obj->extra_flags, OBJEXTRA_ANTI_EVIL );
	}

	af.where	= WHERE_AFFECTS;
	af.type		= sn;
	af.level	= ch->level;
	af.duration = 48;
	af.location	= APPLY_NONE;
	af.modifier = 0;
	af.bitvector= 0;
	affect_to_char( ch, &af );

	ch->println( "You call to the heavens and your cry is heard." );
	ch->println( "A mighty hammer appears in your hands." );
	act( "A fervent look passes across the face of $n.", ch, NULL, NULL, TO_ROOM );
	act( "A hammer suddenly appears in $s hands.", ch, NULL, NULL, TO_ROOM );

	// see if the have a weapon, this will allow removal of cursed items too
	cObj = get_eq_char( ch, WEAR_WIELD );
	if ( cObj ){
		unequip_char( ch, cObj );
	}
	
	obj_to_char( obj, ch );

	return FULL_MANA;
}

/*******************************************************************************/
SPRESULT spell_druidstaff( int, int level, char_data *ch, void *, int )
{
    AFFECT_DATA *af;
	OBJ_INDEX_DATA *pObj;
	OBJ_DATA *obj;
	OBJ_DATA *cObj;
	int numdie, dietype, random, vlevel;

	if (( pObj = get_obj_index( OBJ_VNUM_DRUIDSTAFF )) == NULL )
	{
		ch->printlnf( "Vnum %d not found for Druidstaff, please report to the admin.", OBJ_VNUM_DRUIDSTAFF );
		return NO_MANA;
	}

	// see if the have a built staff in their wield slot
	cObj = get_eq_char( ch, WEAR_WIELD );
	if ( cObj )
	{
		if ( cObj->pIndexData->vnum != OBJ_VNUM_STAFF )
		{
			ch->println( "You must cast this spell on a built staff that you are holding." );
			return NO_MANA;
		}
	}
	else
	{
		ch->println( "You must cast this spell on a built staff that you are holding." );
		return NO_MANA;
	}
	
	obj = create_object( pObj);
	vlevel = UMIN( level, 20 );
	obj->level = vlevel;

	// first try to get a random damage based on level
	random  = number_range( 0, 7 );
	numdie  = weapon_balance_lookup( vlevel, random, 0 );
	dietype = weapon_balance_lookup( vlevel, random, 1 );	

	// damage lookup failed, use polarmost damage class,
	if ( numdie == 0 ||  dietype == 0 )
	{
		numdie  = weapon_balance_lookup( vlevel, 0, 0 );
		dietype = weapon_balance_lookup( vlevel, 0, 1 );
	}


	obj->attune_flags	= ATTUNE_NEED_TO_USE|ATTUNE_PREVIOUS|ATTUNE_ONCE_ONLY;
	obj->attune_id		= ch->id;
	obj->attune_next	= current_time + ICTIME_IRLSECS_PER_DAY;	// 8640 seconds or 144 Minutes :)
	obj->value[1]		= numdie;
	obj->value[2]		= dietype;
	obj->wear_loc		= WEAR_WIELD;			// Set wear loc to the character's inventory

	af					= new_affect();
	af->location		= APPLY_MANA;
	af->modifier		= UMIN( ch->level / 3, 10 );
	af->where			= WHERE_OBJEXTRA;
	af->type			= -1;
	af->duration		= -1;
	af->bitvector		= 0;
	af->level			= vlevel;
	af->next			= obj->affected;
	obj->affected		= af;
	
	act( "A faint green glow passes over $p.", ch, cObj, NULL, TO_CHAR );
	act( "A faint green glow passes over $p held by $n.", ch, cObj, NULL, TO_ROOM );
	extract_obj( cObj );		// Nuke the built staff
	obj_to_char( obj, ch );		// give them the new one

	return FULL_MANA;
}

/*******************************************************************************/
SPRESULT spell_totemstaff( int, int level, char_data *ch, void *, int )
{
	OBJ_INDEX_DATA *pObj;
	OBJ_DATA *obj;
	OBJ_DATA *cObj;
	int numdie, dietype, random, vlevel;

	if (( pObj = get_obj_index( OBJ_VNUM_TOTEMSTAFF )) == NULL )
	{
		ch->printlnf( "Vnum %d not found for Druidstaff, please report to the admin.", OBJ_VNUM_TOTEMSTAFF );
		return NO_MANA;
	}

	// see if the have a druidstaff in their wield slot
	cObj = get_eq_char( ch, WEAR_WIELD );
	if ( cObj )
	{
		if ( cObj->pIndexData->vnum != OBJ_VNUM_DRUIDSTAFF )
		{
			ch->println( "You must cast this spell on a druidstaff that you are holding." );
			return NO_MANA;
		}
	}
	else
	{
		ch->println( "You must cast this spell on a druidstaff that you are holding." );
		return NO_MANA;
	}

	if ( cObj->attune_id != ch->id )
	{
		ch->println( "That is not your staff." );
		return NO_MANA;
	}

	if ( current_time < cObj->attune_next && !IS_IMMORTAL(ch))
	{
		ch->println( "You cannot convert the druidstaff yet." );
		return NO_MANA;
	}
	
	obj = create_object( pObj);
	vlevel = UMIN( level, 30 );
	obj->level = vlevel;

	// first try to get a random damage based on level
	random  = number_range( 0, 7 );
	numdie  = weapon_balance_lookup( vlevel, random, 0 );
	dietype = weapon_balance_lookup( vlevel, random, 1 );	

	// damage lookup failed, use polarmost damage class,
	if ( numdie == 0 ||  dietype == 0 )
	{
		numdie  = weapon_balance_lookup( vlevel, 0, 0 );
		dietype = weapon_balance_lookup( vlevel, 0, 1 );
	}

	obj->attune_flags	= ATTUNE_NEED_TO_USE|ATTUNE_PREVIOUS|ATTUNE_ONCE_ONLY;
	obj->attune_id		= ch->id;
	obj->attune_next	= current_time + ICTIME_IRLSECS_PER_DAY * 2;
	obj->value[1]		= numdie;
	obj->value[2]		= dietype;
	obj->wear_loc		= WEAR_WIELD;			// Set wear loc to the character's inventory

	act( "A mild green glow passes over $p.", ch, cObj, NULL, TO_CHAR );
	act( "A mild green glow passes over $p held by $n.", ch, cObj, NULL, TO_ROOM );
	extract_obj( cObj );		// Nuke the druid staff
	obj_to_char( obj, ch );		// give them the new one

	return FULL_MANA;
}

/*******************************************************************************/
SPRESULT spell_mnemonics(int sn,int level,char_data *ch,void *,int )
{
    AFFECT_DATA af;

	if ( is_affected( ch, sn ))
	{
		ch->println( "You cannot cram any more information into your head." );
		return HALF_MANA;
	}

	af.where		= WHERE_AFFECTS;
	af.type			= sn;
	af.level		= level;
	af.duration		= level;
	af.location		= APPLY_ME;
	af.modifier		= +5;
	af.bitvector	= 0;
	affect_to_char( ch, &af );
	ch->println( "You seem to be able to recall events more clearly." );
	return FULL_MANA;
}

/*******************************************************************************/
SPRESULT spell_logic(int sn,int level,char_data *ch,void *,int )
{
    AFFECT_DATA af;

	if ( is_affected( ch, sn ))
	{
		ch->println( "You are not able to process information any quicker." );
		return HALF_MANA;
	}

	af.where		= WHERE_AFFECTS;
	af.type			= sn;
	af.level		= level;
	af.duration		= level;
	af.location		= APPLY_RE;
	af.modifier		= +5;
	af.bitvector	= 0;
	affect_to_char( ch, &af );
	ch->println( "You seem to be able to reason more effectively." );
	return FULL_MANA;
}

/*******************************************************************************/
SPRESULT spell_clarity(int sn,int level,char_data *ch,void *,int )
{
    AFFECT_DATA af;

	if ( is_affected( ch, sn ))
	{
		ch->println( "You see things as clearly as you are able." );
		return HALF_MANA;
	}

	af.where		= WHERE_AFFECTS;
	af.type			= sn;
	af.level		= level;
	af.duration		= level;
	af.location		= APPLY_IN;
	af.modifier		= +5;
	af.bitvector	= 0;
	affect_to_char( ch, &af );
	ch->println( "You gain insight into the unknown." );
	return FULL_MANA;
}

/*******************************************************************************/
SPRESULT spell_persuasion(int sn,int level,char_data *ch,void *,int )
{
    AFFECT_DATA af;

	if ( is_affected( ch, sn ))
	{
		ch->println( "You are as persuasive as can be." );
		return HALF_MANA;
	}

	af.where		= WHERE_AFFECTS;
	af.type			= sn;
	af.level		= level;
	af.duration		= level;
	af.location		= APPLY_PR;
	af.modifier		= +5;
	af.bitvector	= 0;
	affect_to_char( ch, &af );
	ch->println( "You feel more persuasive." );
	return FULL_MANA;
}

/*******************************************************************************/
SPRESULT spell_lucidity(int sn,int level,char_data *ch,void *,int )
{
    AFFECT_DATA af;

	if ( is_affected( ch, sn ))
	{
		ch->println( "You are already thinking clearly." );
		return HALF_MANA;
	}

	af.where		= WHERE_AFFECTS;
	af.type			= sn;
	af.level		= level;
	af.duration		= level;
	af.location		= APPLY_IN;
	af.modifier		= +5;
	af.bitvector	= 0;
	affect_to_char( ch, &af );
	ch->println( "You feel more lucid." );
	return FULL_MANA;
}

/**************************************************************************/
SPRESULT spell_night_eyes( int sn, int level, char_data *, void *vo, int )
{
	char_data *victim = (char_data *) vo;
	AFFECT_DATA af;

	if(!is_affected(victim,sn))
	{
		af.where = WHERE_RESIST;
		af.type = sn;
		af.level = level;
		af.duration = level/4+10;
		af.location = APPLY_NONE;
		af.modifier = 0;
		af.bitvector   = RES_LIGHT;
		affect_to_char(victim, &af);

		if ( !IS_AFFECTED(victim, AFF_INFRARED ))
		{
			af.where	 = WHERE_AFFECTS;
			af.type      = sn;
			af.level	 = level;
			af.duration  = level/4+10;
			af.location  = APPLY_NONE;
			af.modifier  = 0;
			af.bitvector = AFF_INFRARED;
			affect_to_char( victim, &af );
		}
		victim->println( "Your pupils contract." );
	}
	else
	{
		victim->println( "Your pupils are as small as they will get." );
		return HALF_MANA;
	}
	return FULL_MANA;
}

/*******************************************************************************/
SPRESULT spell_shrink(int sn,int level,char_data *ch,void *vo,int )
{
	char_data *victim = (char_data *) vo;
    AFFECT_DATA af;

	if ( victim->size <= SIZE_SMALL )		// small or tiny
	{
		if ( victim == ch )
		{
			ch->println( "You cannot shrink yourself any smaller." );
			return NO_MANA;
		}
		else
		{
			ch->println( "They cannot be shrunk down any more than they already are." );
			return NO_MANA;
		}
	}

	if ( is_affected( victim, sn ))
	{
		if ( victim == ch )
		{
			ch->println( "You are already in a shrunken state." );
			return HALF_MANA;
		}
		else
		{
			ch->println( "They are already in a shrunken state." );
			return HALF_MANA;
		}
	}

	af.where		= WHERE_AFFECTS;
	af.type			= sn;
	af.level		= level;
	af.duration		= level/4;
	af.location		= APPLY_NONE;
	af.modifier		= 0;
	af.bitvector	= 0;
	affect_to_char( ch, &af );

	victim->println( "You feel yourself shrinking." );

	if ( ch != victim )
		act("$N shrinks to a fraction of $s former size.", ch, NULL, victim, TO_CHAR );
	return FULL_MANA;
}


/*******************************************************************************/
SPRESULT spell_night_of_the_leonids( int sn, int level, char_data *ch, void *, int )
{
	AFFECT_DATA	af;
	char_data *rch;
	int dam;

	if (  ch->in_room->sector_type == SECT_INSIDE
		|| IS_SET( ch->in_room->room_flags, ROOM_INDOORS ))
	{
		ch->println( "You can only call upon the Leonids in the out of doors." );
		return NO_MANA;
	}

	if (   time_info.hour >= HOUR_SUNRISE
		&& time_info.hour <= HOUR_SUNSET )
	{
		ch->println( "This song is only effective at night." );
		return NO_MANA;
	}
	
	ch->println( "Meteors rain from the sky." );
	act( "Meteors rain from the sky.", ch, NULL, NULL, TO_ROOM );

    for ( rch = ch->in_room->people; rch; rch = rch->next_in_room )
	{
		if ( rch->in_room == NULL )
			continue;

		if ( is_affected( rch, gsn_canticle_of_warding ))
			continue;

		if ( is_safe_spell(ch, rch, true))
			continue;

		// damage is level/30 * 20 with half dam done if victim saves vs spell
		dam = ( level / 30 * 20 ) / ( saves_spell( level, rch, DAMTYPE(sn)) ? 2 : 1 );

		damage_spell( ch, rch, dam, sn, DAMTYPE(sn), true );
	}

	if ( IS_SET( ch->in_room->affected_by, ROOMAFF_UTTERDARK ))
		REMOVE_BIT( ch->in_room->affected_by, ROOMAFF_UTTERDARK );

	// check to see if the room is already lit up, no stacked effect
	if ( IS_SET( ch->in_room->affected_by, ROOMAFF_LEONIDS ))
	{
		return FULL_MANA;
	}

	af.where		= WHERE_AFFECTS;
	af.type			= sn;
	af.level		= level;
	af.duration		= 1;
	af.location		= APPLY_NONE;
	af.modifier		= 0;
	af.bitvector	= ROOMAFF_LEONIDS;
						
	affect_to_room( ch->in_room, &af );

	ch->println( "The room is washed in an ethereal glow." );
	act( "The room is washed in an ethereal glow.", ch, NULL, NULL, TO_ROOM );
	return FULL_MANA;
}
/*******************************************************************************/
SPRESULT spell_canticle_of_warding( int, int, char_data *, void *, int )
{
	return NO_MANA;
}
/*******************************************************************************/
/*******************************************************************************/