mud_dist/area/
/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *                                                                         *
 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
 *  Chastain, Michael Quan, and Mitchell Tse.                              *
 *                                                                         *
 *  Envy Diku Mud improvements copyright (C) 1994 by Michael Quan, David   *
 *  Love, Guilherme 'Willie' Arnold, and Mitchell Tse.                     *
 *                                                                         *
 *  In order to use any part of this Envy Diku Msud, you must comply with  *
 *  the original Diku license in 'license.doc', the Merc license in        *
 *  'license.txt', as well as the Envy license in 'license.nvy'.           *
 *  In particular, you may not remove either of these copyright notices.   *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  *
 ***************************************************************************/

/*$Id: cls_rng.c,v 1.50 2005/03/23 14:47:01 ahsile Exp $*/

#if defined( macintosh )
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <math.h>

#include "merc.h"
char* target_name;

int spell_force_of_nature( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA  *victim = (CHAR_DATA *) vo;
    AFFECT_DATA af;
    
    if ( IS_AFFECTED4( victim, AFF_FORCE_OF_NATURE ) )
    {
        affect_strip(victim, sn);
        if(skill_table[sn].msg_off)
        {
            send_to_char(C_DEFAULT, skill_table[sn].msg_off, victim );
            send_to_char(C_DEFAULT, "\n\r", victim );
        }
        act(C_DEFAULT, skill_table[sn].msg_off_room, victim, NULL, NULL, TO_NOTVICT);
        victim->shields -= 1;
        return SKPELL_NO_DAMAGE;
    }
         
    if ( !IS_SHIELDABLE( victim ) )
        return SKPELL_MISSED;
        
    af.type      = sn;
    af.level     = level;
    af.duration  = -1;
    af.location  = APPLY_HITROLL;
    if( !IS_NPC( ch ) )
    {
	af.modifier = ( ( ch->level + ch->pcdata->learned[sn] / 10 ) ) * 2 / 3;
    }
    else
    {
	af.modifier = ( ch->level + 100 ) * 2 / 3;
    }
    af.bitvector = AFF_FORCE_OF_NATURE;
    affect_to_char4( victim, &af );

    af.location  = APPLY_DAMROLL;
    if( !IS_NPC( ch ) )
    {
	af.modifier = ( ch->level + ( ch->pcdata->learned[sn] / 10 )  ) * 2 / 3;
    }
    else
    {
	af.modifier = ( ch->level + 100 ) * 2 / 3;
    }
    affect_to_char4( victim, &af );

    af.location  = APPLY_STR;
    af.modifier  =  ch->level / 10;
    affect_to_char4( victim, &af );

    af.location  = APPLY_DEX;
    af.modifier  =  ch->level / 10;
    affect_to_char4( victim, &af );

    af.location  = APPLY_SAVING_SPELL;
    if( !IS_NPC( ch ) )
    {
	af.modifier = ( ch->level + ( ch->pcdata->learned[sn] / 10 )  ) / 3 * -1;
    }
    else
    {
	af.modifier = ( ch->level + 100 ) * 2 / 3 * -1;
    }
    affect_to_char4( victim, &af );

    victim->shields += 1;
    
    send_to_char(AT_GREEN, "Your soul is fused with a force of nature.\n\r", victim );
    act(AT_GREEN, "$n's soul is fused with a force of nature.", victim, NULL, NULL, TO_ROOM );
    return SKPELL_NO_DAMAGE;
}   

int spell_forestwalk( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA  *victim = (CHAR_DATA *) vo;
    AFFECT_DATA af;   

    if ( victim->position == POS_FIGHTING )
	return SKPELL_BOTCHED;

    if ( is_affected( victim, sn ) )
    {
	affect_strip(victim, sn);
	if(skill_table[sn].msg_off)
	{
	    send_to_char(C_DEFAULT, skill_table[sn].msg_off, victim );
	    send_to_char(C_DEFAULT, "\n\r", victim );
	}
        act(C_DEFAULT, skill_table[sn].msg_off_room, victim, NULL, NULL, TO_NOTVICT);
        return SKPELL_NO_DAMAGE;
    }
    
    af.type      = sn;
    af.level     = level;
    af.duration  = -1;
    af.location  = APPLY_NONE;
    af.modifier  = level;
    af.bitvector = 0;
    affect_to_char( victim, &af );

    if ( ch != victim )
        send_to_char(AT_DGREEN, "You call forth the power of the forests.\n\r", ch );
    send_to_char(AT_DGREEN, "The power of the forests rests upon you.\n\r", victim );
    return SKPELL_NO_DAMAGE;
}

int spell_mountainwalk( int sn, int level, CHAR_DATA *ch, void *vo )         
{       
    CHAR_DATA  *victim = (CHAR_DATA *) vo;
    AFFECT_DATA af;

    if ( victim->position == POS_FIGHTING )
	return SKPELL_BOTCHED;

    if ( is_affected( victim, sn ) )
    {
	affect_strip(victim, sn);
	if(skill_table[sn].msg_off)
	{
	    send_to_char(C_DEFAULT, skill_table[sn].msg_off, victim );
	    send_to_char(C_DEFAULT, "\n\r", victim );
	}
        act(C_DEFAULT, skill_table[sn].msg_off_room, victim, NULL, NULL, TO_NOTVICT);
        return SKPELL_NO_DAMAGE;
    }
    
    af.type      = sn;
    af.level     = level;
    af.duration  = -1;        
    af.location  = APPLY_NONE;
    af.modifier  = level;    
    af.bitvector = 0;
    affect_to_char( victim, &af );
     
    if ( ch != victim )
        send_to_char(AT_ORANGE, "You call forth the power of the mountains and hills.\n\r", ch );                
    send_to_char(AT_ORANGE, "The power of the mountains and hills rests upon you.\n\r", victim );                    
    return SKPELL_NO_DAMAGE;
}

int spell_plainswalk( int sn, int level, CHAR_DATA *ch, void *vo )         
{       
    CHAR_DATA  *victim = (CHAR_DATA *) vo;
    AFFECT_DATA af;

    if ( victim->position == POS_FIGHTING )
	return SKPELL_BOTCHED;

    if ( is_affected( victim, sn ) )
    {
	affect_strip(victim, sn);
	if(skill_table[sn].msg_off)
	{
	    send_to_char(C_DEFAULT, skill_table[sn].msg_off, victim );
	    send_to_char(C_DEFAULT, "\n\r", victim );
	}
        act(C_DEFAULT, skill_table[sn].msg_off_room, victim, NULL, NULL, TO_NOTVICT);
        return SKPELL_NO_DAMAGE;
    }
    
    af.type      = sn;
    af.level     = level;
    af.duration  = -1;        
    af.location  = APPLY_NONE;
    af.modifier  = level;    
    af.bitvector = 0;
    affect_to_char( victim, &af );
     
    if ( ch != victim )
        send_to_char(AT_YELLOW, "You call forth the power of the plains and deserts.\n\r", ch );                
    send_to_char(AT_YELLOW, "The power of the plains and deserts rests upon you.\n\r", victim );                    
    return SKPELL_NO_DAMAGE;
}

int spell_swampwalk( int sn, int level, CHAR_DATA *ch, void *vo )         
{       
    CHAR_DATA  *victim = (CHAR_DATA *) vo;
    AFFECT_DATA af;

    if ( victim->position == POS_FIGHTING )
	return SKPELL_BOTCHED;

    if ( is_affected( victim, sn ) )
    {
	affect_strip(victim, sn);
	if(skill_table[sn].msg_off)
	{
	    send_to_char(C_DEFAULT, skill_table[sn].msg_off, victim );
	    send_to_char(C_DEFAULT, "\n\r", victim );
	}
        act(C_DEFAULT, skill_table[sn].msg_off_room, victim, NULL, NULL, TO_NOTVICT);
        return SKPELL_NO_DAMAGE;
    }
    
    af.type      = sn;
    af.level     = level;
    af.duration  = -1;        
    af.location  = APPLY_NONE;
    af.modifier  = level;    
    af.bitvector = 0;
    affect_to_char( victim, &af );
     
    if ( ch != victim )
        send_to_char(AT_PINK, "You call forth the power of the swamps.\n\r", ch );                
    send_to_char(AT_PINK, "The power of the swamps rests upon you.\n\r", victim );                    
    return SKPELL_NO_DAMAGE;
}

int spell_thunder_strike( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *victim       = (CHAR_DATA *) vo;
    static const int        dam_each [ ] =
    {
          0,
          0,   0,   0,   0,   0,          0,   0,   0,   0,   0,
          0,   0,   0,   0,  30,         35,  40,  45,  50,  55,
         60,  65,  70,  75,  80,         82,  85,  90,  95, 100,
        105, 110, 115, 120, 125,        130, 135, 140, 145, 150,
        155, 160, 165, 170, 175,        180, 185, 190, 195, 200,
        205, 210, 215, 220, 225,        230, 235, 240, 245, 250,
        252, 254, 256, 258, 260,        262, 264, 266, 268, 270,
        272, 274, 276, 278, 280,        282, 284, 286, 288, 290,
        292, 394, 396, 398, 300,        302, 304, 306, 308, 310,
        315, 320, 325, 330, 335,        340, 345, 350, 355, 360
    };
    int        dam;
     
    level    = UMIN( level, sizeof( dam_each ) / sizeof( dam_each[0] ) - 1 );
    level    = UMAX( 0, level );
    dam      = number_range( dam_each[level] / 2, dam_each[level] * 5 );
    if ( IS_OUTSIDE( ch ) )   
    {
		dam = (int) (dam * 1.5);
        if ( weather_info.sky < SKY_RAINING )
        {
            dam /= 2;
        }
        if ( weather_info.sky > SKY_RAINING )
        {
            send_to_char(AT_WHITE, "The bad weather increases the spells power!\n\r", ch );
            dam *= 2;
        }
    }
    
    if ( saves_spell( level, victim ) )
        dam /= 2;
    //damage( ch, victim, dam, sn );
    return dam;
}

int  spell_lightning_storm( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *vch;
    int        dam;

    send_to_char(AT_BLUE, "You call forth a thunderous storm!\n\r", ch );
    act(AT_BLUE, "$n calls forth a thunderous storm.", ch, NULL, NULL, TO_ROOM );
        
    if ( IS_SET( ch->in_room->room_flags, ROOM_SAFE))
    {
	send_to_char(AT_WHITE, "You are in a safe room!", ch);
	return SKPELL_MISSED;
    }
        
    for ( vch = char_list; vch; vch = vch->next )
    {
	if ( vch->deleted || !vch->in_room || vch == ch )
	    continue;

	dam = number_range( ch->level*2, ch->level * 7 );
	if ( vch->in_room == ch->in_room )
	{
	    if ( IS_OUTSIDE( ch ) )
	    {
		dam = (int) (dam * 1.5);
		if ( weather_info.sky < SKY_RAINING )
		{
		    dam /= 2;
		}
		if ( weather_info.sky > SKY_RAINING )
		{
		    send_to_char(AT_WHITE, "The bad weather increases the spells power!\n\r", ch );
		    dam *= 2;
		}
	    }
	    if ( saves_spell( level, vch ) )
		dam /= 2;

	    damage( ch, vch, dam, sn );
	    continue;
	}
        
	if ( vch->in_room->area == ch->in_room->area )
	    send_to_char(AT_ORANGE, "The earth trembles and shivers.\n\r", vch );
    }
        
    return SKPELL_NO_DAMAGE;
}    

int spell_friend_of_nature( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA  *victim = (CHAR_DATA *) vo;
    AFFECT_DATA af;
    
    if ( IS_AFFECTED( victim, AFF_PEACE) )
        return SKPELL_MISSED;
        
    af.type      = sn;
    af.level     = level;
    af.duration  = number_fuzzy( level / 5 );
    af.location  = APPLY_NONE;
    af.modifier  = 0;
    af.bitvector = AFF_PEACE;
    affect_to_char( victim, &af );
    
    send_to_char(AT_BLUE, "You the protective forces of nature come over you.\n\r", victim );
    act(AT_BLUE, "$n looks like he is one with nature.", victim, NULL, NULL, TO_ROOM );
    return SKPELL_NO_DAMAGE;
}

int  spell_refreshing_rain( int sn, int level, CHAR_DATA *ch, void *vo )
{
    CHAR_DATA *vch;
    
    send_to_char(AT_BLUE, "You enchant the heavens to rain a healing water.\n\r", ch );
    act(AT_ORANGE, "$n causes the heavens to rain a healing rain.", ch, NULL, NULL, TO_ROOM );
    
    for ( vch = char_list; vch; vch = vch->next )
    {
        if ( vch->deleted || !vch->in_room )
            continue;
        if ( vch->in_room == ch->in_room )
        {
	    if( IS_OUTSIDE( ch ) )
	    {
		spell_heal( skill_lookup("heal"), ch->level + 50, ch, vch );
	    }
	    else
	    {
		spell_heal( skill_lookup("heal"), ch->level / 2, ch, vch );
	    }
            continue;
        }
    }
  
    return SKPELL_NO_DAMAGE;
}

int spell_storm_seeker(int sn, int level, CHAR_DATA *ch, void *vo)
{
    CHAR_DATA  *victim = (CHAR_DATA *) vo;
    AFFECT_DATA af;
    int loss;

    if ( is_affected( victim, sn ))
    {
	send_to_char(AT_RED, "A curse has already been inflicted.\n\r", ch );
	return SKPELL_MISSED;
    }
        
    if( IS_OUTSIDE( ch ) )
    {
	loss = number_fuzzy( ch->level * 2 / 3 );
    }
    else
    {
	loss = number_fuzzy( ch->level * 2 / 4 );
    }
    
    af.type       = sn;
    af.level      = level;
    af.duration   = level / 6;
    af.location   = APPLY_SAVING_SPELL;
    af.modifier   = loss;
    af.bitvector  = AFF_CURSE;
    affect_to_char( victim, &af );
  
    af.location  = APPLY_DAM_WIND;
    af.modifier  = 0 - loss;
    af.bitvector = AFF_CURSE;
    affect_to_char( victim, &af );
     
    if(ch != victim)
	send_to_char(AT_GREEN, "Ok.\n\r", ch );

    send_to_char(AT_GREEN, "A lightning bolt strikes you square in the chest.\n\r", victim);
    spell_lightning_bolt( skill_lookup("lightning bolt"), ch->level, ch, victim );

    return SKPELL_NO_DAMAGE;
}

int spell_essence_of_gaia( int sn, int level, CHAR_DATA *ch, void *vo )
{   
    CHAR_DATA  *victim = (CHAR_DATA *) vo;
    AFFECT_DATA af;
    
    if ( IS_AFFECTED4( victim, AFF_ESSENCE_OF_GAIA ) )
    {
        affect_strip(victim, sn);
        if(skill_table[sn].msg_off)
        {
            send_to_char(C_DEFAULT, skill_table[sn].msg_off, victim );
            send_to_char(C_DEFAULT, "\n\r", victim );
        }
        act(C_DEFAULT, skill_table[sn].msg_off_room, victim, NULL, NULL, TO_NOTVICT);
        victim->shields -= 1;
        return SKPELL_NO_DAMAGE;
    }
            
    if ( IS_AFFECTED2( victim, AFF_GOLDEN_ARMOR ) || IS_AFFECTED4( victim, AFF_GOLDEN_SANCTUARY ) || IS_AFFECTED4( victim, AFF_BIOFEEDBACK ) || IS_AFFECTED( victim, AFF_SANCTUARY ) )
        return SKPELL_MISSED;
            
    if ( !IS_SHIELDABLE( victim ) )
        return SKPELL_MISSED;
            
    af.type      = sn;
    af.level     = level;
    af.duration  = -1;
    af.location  = APPLY_NONE;
    af.modifier  = 0;
    af.bitvector = AFF_ESSENCE_OF_GAIA;
    affect_to_char4( victim, &af );
    victim->shields += 1;
 
    send_to_char(AT_WHITE, "You are surrounded by Gaia's essence.\n\r", victim );
    act(AT_WHITE, "$n is surrounded by Gaia's essence.", victim, NULL, NULL, TO_ROOM );
    return SKPELL_NO_DAMAGE;
}

int skill_lightning_arrow( int sn, int level, CHAR_DATA *ch, void *vo )
{
    ROOM_INDEX_DATA* in_room = NULL;
    ROOM_INDEX_DATA* to_room = NULL;
    OBJ_DATA*  bow;
    OBJ_DATA*  ammo;
    CHAR_DATA* victim	= NULL;
    int        distance = 0;
    int        target	= 0;
    int	       dam		= 0;
    char       buf[MAX_STRING_LENGTH];

    /* check conditions */
    if (!IS_NPC(ch) &&  number_percent() > ( ch->pcdata->learned[sn] / 10 ) )
    {
	send_to_char(C_DEFAULT, "You failed.\n\r", ch);
	return SKPELL_MISSED;
    }
 
    if ( ! (bow 	   = get_eq_char(ch, WEAR_WIELD)	) 
	|| (bow->value[3] != flag_value (weapon_flags, "shot") )
	|| (bow->value[0] != flag_value (ammo_flags, "arrow") 	) )
    {
	send_to_char(AT_WHITE, "You need a BOW and arrows to shoot!\n\r", ch);
	return SKPELL_MISSED;
    } else if (!(ammo = find_arrows( ch ) ) )
    {
	send_to_char(AT_WHITE, "You need a bow and ARROWS to shoot!\n\r", ch);
	return SKPELL_MISSED;
    }

    /* calculate damage */
    dam = 100;

    if ( (target = find_missle_target(sn, ch, (char*) target_name, &victim, &to_room, &distance) ) )
    {
	ammo->value[0]--;
	act( AT_BLUE, "$n draws $s weapon and fires a lightning arrow!", ch, NULL, NULL, TO_ROOM );

	if (!ammo->value[0])
		ammo->deleted = TRUE;

	if (target == SHOOT_HERE)
	{
		if (ch->fighting == victim)
			return dam;
		else
		{
			damage( ch, victim, dam, sn);
			multi_hit( victim, ch, TYPE_UNDEFINED  ); /* start a fight */
		}
	}

	in_room = ch->in_room;
	if (in_room != to_room)
	{
		char_from_room( ch );
		char_to_room( ch, to_room );
	}

	if ( target == SHOOT_DOOR )
	{
		sprintf(buf, "Your lightning arrow flies %d rooms away and strikes something solid.", distance);
		act( AT_BLUE, buf, ch, NULL, NULL, TO_CHAR );
		act( AT_BLUE, "A lightning arrow flies into the area and strikes something solid.", ch, NULL, NULL, TO_ROOM );
	}
	else if (target == SHOOT_DIST )
	{
		sprintf(buf, "Your lightning arrow flies %d rooms away and falls harmlessly to the ground.\n\r", distance);
		send_to_char(AT_BLUE, buf, ch);
	} 
	else if (target == SHOOT_FOUND )
	{
		act( AT_BLUE, "A lightning arrow flies into the area and hits $N!", ch, NULL, victim, TO_NOTVICT );
		sprintf(buf, "Your lightning arrow flies %d rooms away and hits $N!", distance);
		act( AT_BLUE, buf, ch, NULL, victim, TO_CHAR);
		act( AT_BLUE, "$n's lightning arrow flies into the area and hits YOU!" , ch, NULL, victim, TO_VICT ); 
		damage( ch, victim, (int) ( dam / (distance + 1) ), sn );
	}

	char_from_room( ch );
	char_to_room( ch, in_room );
    } 

    return SKPELL_NO_DAMAGE;
}