FlCodebase3.1/
FlCodebase3.1/bounty/
FlCodebase3.1/challenge/
FlCodebase3.1/clans/
FlCodebase3.1/gods/
FlCodebase3.1/mobprogs/
FlCodebase3.1/player/
FlCodebase3.1/savemud/
/***************************************************************************
 *  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.                              *
 *                                                                         *
 *  In order to use any part of this Envy Diku Mud, 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.                                                  * 
 *                                                                         *
 *      ROM 2.4 is copyright 1993-1998 Russ Taylor                         *
 *      ROM has been brought to you by the ROM consortium                  *
 *          Russ Taylor (rtaylor@hypercube.org)                            *
 *          Gabrielle Taylor (gtaylor@hypercube.org)                       *
 *          Brian Moore (zump@rom.org)                                     *
 *      By using this code, you have agreed to follow the terms of the     *
 *      ROM license, in the file Rom24/doc/rom.license                     *
 *                                                                         *
 * Code Adapted and Improved by Abandoned Realms Mud                       *
 * and Aabahran: The Forsaken Lands Mud by Virigoth                        *
 *                                                                         *
 * Continued Production of this code is available at www.flcodebase.com    *
 ***************************************************************************/

#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"
#include "magic.h"
#include "song.h"
#include "recycle.h"
#include "interp.h"

extern char *target_name;
extern int eq_positions[24];

/* Contains the tattoo spells/functions */

/* PALISON */
void tattoo_tick_palison(CHAR_DATA* ch, OBJ_DATA* tattoo){

  CHAR_DATA* vch = ch->fighting;
  /* All we do here is cast sear at 11/12/13 hours if we are fighting. */

  if (vch == NULL || mud_data.time_info.hour < 11 || mud_data.time_info.hour > 13)
    return;

  if ( !IS_OUTSIDE(ch) || IS_SET(ch->in_room->room_flags, ROOM_DARK))
    return;

  act("$p flares brightly as sun's rays fall upon its surface!", ch, tattoo, vch, TO_ALL);
  spell_sear(skill_lookup("sear"), ch->level, ch, vch, TARGET_CHAR);
}

/* Virigoth */
CHAR_DATA* undead_check_guard(CHAR_DATA* ch, CHAR_DATA* mob)
{
  const int MAX_CHS = 12;

  CHAR_DATA* och;
  CHAR_DATA* och_next;
  AFFECT_DATA af;

  CHAR_DATA* chs[MAX_CHS];

  int tot_chs = 0;
  
/* Put all avaliable saving chars in an array */
  for ( och = ch->in_room->people; och != NULL; och = och_next ){
    och_next = och->next_in_room;
	
    if (!IS_NPC(och) || !IS_UNDEAD(och)
	|| !can_see(och, ch)
	|| och->level > ch->level
	|| och->fighting == ch
	|| ch->fighting == och
	|| och == mob
	|| (och->master != NULL && och->master != ch)
	)
      continue;

    chs[tot_chs++] = och;
  }//end for

  /* now we pick one character out of all possible choices */
  if (tot_chs == 0)
    return NULL;
  /* we return a random pick */  
  och =  chs[number_range(0, UMAX(0, tot_chs - 1))];
  //set temporary charm flag to prevent from fleeing.
  af.type = gsn_charm_person;
  af.level = ch->level;
  af.duration = 1 + number_fuzzy(1);
  af.where = TO_AFFECTS;
  af.bitvector = AFF_CHARM;
  af.location = APPLY_NONE;
  af.modifier = 0;
  if (!IS_AFFECTED(och, AFF_CHARM))
    affect_to_char(och, &af);
  return och;
}

/* Tatto spell for Virigoth tattoo, not usuable by normal means */
void spell_darklife( int sn, int level, CHAR_DATA *ch, void *vo,int target )
{
  //This is basicly a shadowstalk spell except it lasts only a single combat round.
  CHAR_DATA* victim = ch->fighting;
  CHAR_DATA *shadow;
  OBJ_DATA *wield;
  int i;
  char buf[MSL];
  char *name;
  
  if (victim == NULL)
    {
      send_to_char("You must be in combat.\n\r", ch);
      return;
    }
  if (ch->fighting != victim)
    {
      send_to_char("You must be in combat.\n\r", ch);
      return;
    }

  if (ch->class == class_lookup("vampire")
      || ch->class == class_lookup("necromancer")){
    spell_weaken( gsn_weaken, level, ch, ch->fighting, target );
    return;
  }

  if (room_has_sun(ch->in_room))
    {
      send_to_char("The light banishes your shadow as it takes life of its own.\n\r", ch);
      return;
    }

  send_to_char("Your shadow seems to take on a life of its own!\n\r", ch); 
  act("$n's shadow takes on a life of its own!",ch,NULL,NULL,TO_ROOM);

  shadow = create_mobile( get_mob_index(MOB_VNUM_SHADOW) );
  for (i=0;i < MAX_STATS; i++)
    shadow->perm_stat[i] = ch->perm_stat[i];
  
  shadow->max_hit = ch->max_hit;
  shadow->hit = shadow->max_hit;
  shadow->max_mana = ch->max_mana;
  shadow->mana = shadow->max_mana;
  shadow->level = ch->level - 2;
  for (i=0; i < 3; i++)
    shadow->armor[i] = ch->armor[i];
  shadow->armor[3] =ch->armor[3];
  shadow->sex = ch->sex;  
  shadow->gold = 0;
    
//Now we copy over little things like weapon stats.
  shadow->damroll = ch->damroll;
  shadow->hitroll = ch->hitroll;
    
  if ( (wield = get_eq_char(ch,WEAR_WIELD)) != NULL)
    {
      shadow->damage[DICE_NUMBER] = wield->value[1];
      shadow->damage[DICE_TYPE] = wield->value[2];
      shadow->dam_type = wield->value[3];
    }
 

  name = IS_NPC(ch) ? ch->short_descr : ch->name;
  sprintf( buf, shadow->short_descr, name );
  free_string( shadow->short_descr );
  shadow->short_descr = str_dup( buf );
  
  sprintf( buf, shadow->long_descr, name );
  free_string( shadow->long_descr );
  shadow->long_descr = str_dup( buf );
  
  sprintf( buf, shadow->description, name );
  free_string( shadow->description );
  shadow->description = str_dup( buf );
  
  char_to_room(shadow,ch->in_room);

  //set char flags so mobs dont flee from it.
  SET_BIT(shadow->affected_by, AFF_CHARM);
  
  //stripsome usless flags that come with the shadowstalk mob
  affect_strip ( shadow, gsn_invis			);
  affect_strip ( shadow, gsn_mass_invis			);
  REMOVE_BIT   ( shadow->affected_by, AFF_INVISIBLE	);
  
  affect_strip( shadow, gsn_hide );
  REMOVE_BIT   ( shadow->affected_by, AFF_HIDE		);
  
  //we make the shadow attack and disappear.
  //add a leader/charm here to give exp on kills
  shadow->leader = ch;
  SET_BIT(shadow->affected_by, AFF_CHARM);
  multi_hit(shadow, victim, shadow->dam_type + TYPE_HIT);
  extract_char(shadow, TRUE);
}//end spell.


/* Over lay to beckon social */
void do_beckon(CHAR_DATA *ch, char *argument){

    char arg[MIL];
    CHAR_DATA *victim;
    bool fFol = TRUE;


    /* Now check if the target should follow */
    one_argument(argument,arg);

    if (ch->tattoo != deity_lookup("cycle"))
      fFol = FALSE;

    if (arg[0] == '\0')
      fFol = FALSE;


    if ((victim = get_char_room(ch, NULL, arg)) == NULL){
      fFol = FALSE;
      check_social(ch, "beckon", argument);
      return;
    }

    if (victim->fighting != NULL
	|| !IS_NPC(victim)
	|| !IS_UNDEAD(victim)
	|| IS_SET(victim->act, ACT_TOO_BIG)
	|| victim->level > 4 * ch->level / 5)
      fFol = FALSE;


    if (!fFol)
      {
	check_social(ch, "beckon", argument);
	return;
      }

    if ( (IS_EVIL(ch) && IS_GOOD(victim))
	 || (IS_EVIL(victim) && IS_GOOD(ch)) ){
      send_to_char("You have a feeling that your align forbids them from following you.\n\r", ch);
      return;
    }

    //message
    act("You beckon for $N to follow.", ch, NULL, victim, TO_CHAR);
    act("$n beckons $N to follow...hmmm what's going on?", ch, NULL, victim, TO_NOTVICT);
    act("$n beckons for you to follow.", ch, NULL, victim, TO_VICT);

    //make the character a follower
    if (ch->pet)
      {
	if (ch->pet->in_room == victim->in_room){
	  if (ch->pet == victim)
	    act("$n points at $mself obviously confused.", victim, NULL, NULL, TO_ROOM);
	  else
	    act("$n glances meaningfully at $N and turns away.", victim, NULL, ch->pet, TO_ROOM);
	}
	else
	  act("$n mumbles something about $N then turns away.", victim, NULL, ch->pet, TO_ROOM);
	return;
      }
    else if (!IS_NPC(ch) && ch->pcdata->familiar)
      {
	if (ch->pcdata->familiar->in_room == victim->in_room){
	  if (ch->pcdata->familiar == victim)
	    act("$n points at $mself obviously confused.", victim, NULL, NULL, TO_ROOM);
	  else
	    act("$n glances meaningfully at $N and turns away.", victim, NULL, ch->pcdata->familiar, TO_ROOM);
	}
	else
	  act("$n mumbles something about $N then turns away.", victim, NULL, ch->pcdata->familiar, TO_ROOM);
	return;
      }
    else if ( victim->master){
      if (victim->master->in_room == victim->in_room)
	act("$n glances meaningfully at $N and turns away.", victim, NULL, victim->master, TO_ROOM);
      else
	act("$n mumbles something about $N then turns away.", victim, NULL, victim->master, TO_ROOM);
      return;
    }


    act("$N glances at $n's tattoo and obediently follows $m.", ch, NULL, victim, TO_ROOM);
    act("$N glances at your tattoo and $S eyes widen in fear.", ch, NULL, victim, TO_CHAR);

    SET_BIT(victim->affected_by, AFF_CHARM);
    victim->comm = COMM_NOTELL|COMM_NOYELL|COMM_NOCHANNELS;
    SET_BIT(victim->act, ACT_PET);

    REMOVE_BIT(victim->act, ACT_AGGRESSIVE);
    victim->hunting = NULL;

    add_follower(victim,ch);
    victim->leader = ch;
    ch->pet = victim;

}//end beckon

/* summons a demon for 1 tick */
void spell_demon_summon( int sn, int level, CHAR_DATA *ch, void *vo, int target )
{
    CHAR_DATA *demon;
    AFFECT_DATA af;

    int i;

    if (is_affected(ch,sn))
	return;

    if (get_control(ch, MOB_VNUM_DEMON) > 0)
	return;

    act("A demon comes to your aid!",ch,NULL,NULL,TO_CHAR);
    act("A demon comes to $n's aid!",ch,NULL,NULL,TO_ROOM);

    demon = create_mobile( get_mob_index(MOB_VNUM_DEMON) );
    for (i=0;i < MAX_STATS; i++)
	demon->perm_stat[i] = ch->perm_stat[i];
    demon->max_hit = IS_NPC(ch)? URANGE(ch->max_hit,1 * ch->max_hit,30000) : URANGE(ch->pcdata->perm_hit,1*ch->pcdata->perm_hit,30000);
    demon->hit = demon->max_hit;
    demon->max_mana = IS_NPC(ch)? ch->max_mana : ch->pcdata->perm_mana;
    demon->mana = demon->max_mana;
    demon->level = ch->level / 2;
    for (i=0; i < 3; i++)
	demon->armor[i] = interpolate(demon->level,100,-100);
    demon->armor[3] = interpolate(demon->level,100,0);
    demon->comm = COMM_NOTELL|COMM_NOYELL|COMM_NOCHANNELS;
    demon->summoner = ch;
    char_to_room(demon,ch->in_room);

    af.type               = gsn_timer;
    af.level              = level; 
    af.duration           = 0;
    af.bitvector          = 0;
    af.modifier           = 0;
    af.location           = APPLY_NONE;
    affect_to_char(demon, &af);  
    SET_BIT(demon->affected_by, AFF_CHARM);
    add_follower(demon,ch);
    demon->leader = ch;
}

/* if in forest mountain field, vegetaion lags the person for 2 ticks. */
void spell_verdigar_tat( int sn, int level, CHAR_DATA *ch, void *vo, int target ){
  CHAR_DATA* victim = (CHAR_DATA*) vo;

  int sector = ch->in_room->sector_type;
  /* Viri: Give same funcionatliy to all calsses
     with added bonus of pet -hide for rangers */

  if (ch->class == class_lookup("ranger"))
    return;

  if (sector != SECT_FOREST && sector != SECT_FIELD 
      && sector != SECT_HILLS && sector != SECT_MOUNTAIN){
    act("Few tiny roots sprout from the soil then wither on the hard ground.\n\r", ch, NULL, NULL, TO_ALL);
    return;
  }

  act("Roots and plants lash at you binding you to the ground!", victim, NULL, NULL, TO_CHAR);
  act("Roots and plants lash at $n binding $m to the ground!", victim, NULL, NULL, TO_ROOM);

  if (IS_AFFECTED(victim, AFF_FLYING) && !is_affected(victim, gsn_thrash)){
    AFFECT_DATA af;
    af.where	= TO_AFFECTS;
    af.type   = gsn_thrash;
    af.level  = ch->level;
    af.duration = 0;
    af.modifier = 0;
    af.location = 0;
    af.bitvector = 0;
    affect_to_char(victim,&af);
    act("You can't seem to get back into the air",victim,NULL,NULL,TO_CHAR);
    act("$n can't seem to get back into the air",victim,NULL,NULL,TO_ROOM);

    WAIT_STATE2(victim, skill_table[sn].beats);
  }
}

/* Eirik tattoo spell, makes person always visible to the one who marked them */
void spell_mark_prey( int sn, int level, CHAR_DATA *ch, void *vo,int target )
{
    CHAR_DATA *victim = (CHAR_DATA *) vo;
    AFFECT_DATA af, *paf;

    if (is_affected(victim, gsn_mark_prey))
      return;
    if ( saves_spell( level, victim,DAM_OTHER,skill_table[sn].spell_type) ){
      return;
    }
    af.where     = TO_AFFECTS;
    af.type      = gsn_mark_prey;
    af.level	 = level;
    af.duration  = number_range(4, 6);
    af.location  = APPLY_NONE;
    af.modifier  = 0;
    af.bitvector = 0;
    paf = affect_to_char( victim, &af );
    string_to_affect(paf, ch->name);
    act_new( "You sense you have been marked somehow.", victim, NULL, NULL, TO_CHAR, POS_DEAD );
    act( "$n has been marked by $G's power.", victim, NULL, ch, TO_ROOM );
}

/* Tattoo spell for Sirantnot usable otherwise */
void spell_swords_to_plows( int sn, int level, CHAR_DATA *ch, void *vo,int target ){
  /* 
     spell takes a difference between the caster's and victims rares
     if the difference is positive it gets a chance based on quadratic
     increase on the difference, and if chance roll paces a single rare
     on the victim gets turned into a relativly worthless item.

     Description of the worthless item is  based on item type.
  */
  const int max_rare = 25;

  CHAR_DATA* victim = (CHAR_DATA*) vo;
  OBJ_DATA* obj;
  OBJ_DATA* rares[max_rare];

  int chance = 0;
  int ch_rare = 0;
  int ch_worn = 0;
  int vch_rare = 0;
  int i = 0;



  if (victim == NULL || IS_NPC(victim)
      || IS_IMMORTAL(victim))
    return;

  /* check if the ch is not near naked to prevent abuse */
  for (i = 0; i < sizeof(eq_positions)/sizeof(eq_positions[0]); i++){
    if ( ( obj = get_eq_char( ch, eq_positions[i] ) ) != NULL )
      ch_worn ++;
  }
  if (ch_worn < (2 * (sizeof(eq_positions)/sizeof(eq_positions[0])) / 3)
      && !IS_IMMORTAL(ch))
    return;

  /* count rares on ch */
  for ( obj = ch->carrying; obj != NULL; obj = obj->next_content ){
    if (IS_LIMITED(obj) && !IS_SET(obj->wear_flags, ITEM_HAS_OWNER))
      ch_rare ++;
  }
  /* count rares on victim and prep them for selection */
  for ( obj = victim->carrying; obj != NULL; obj = obj->next_content ){
    if (IS_LIMITED(obj) && !IS_SET(obj->wear_flags, ITEM_HAS_OWNER)){
      rares[++vch_rare] = obj;
    }
  }
  /* get the chance */
  chance = (vch_rare - ch_rare) * (vch_rare - ch_rare) / 2;
  chance += get_curr_stat(ch,STAT_LUCK) - get_curr_stat(victim,STAT_LUCK);

  if (number_percent() > chance)
    return;

  /* get a random rare to convert */
  if (vch_rare)
    obj = rares[number_range(1, vch_rare)];
  else
    return;

  act("Before your eyes $p shimmers and changes.", victim, obj, NULL, TO_ALL);

  /* now we start converting it */
  {
    AFFECT_DATA* paf;

    obj->enchanted = TRUE;
    for (paf = obj->affected; paf != NULL; paf = paf->next)
      free_affect(paf);
    /* get rid of rare etc. */
    REMOVE_BIT(obj->wear_flags, ITEM_RARE);
    REMOVE_BIT(obj->wear_flags, ITEM_UNIQUE);
    /* extras*/
    obj->extra_flags = 0;

    /* reset the values */
    if (obj->item_type != ITEM_SCROLL
	&& obj->item_type != ITEM_STAFF
	&& obj->item_type != ITEM_POTION){
      obj->value[1] = 5;
      obj->value[2] = 5;
    } 
    /* set name short and long desc. */
    {
      char* name = item_name(obj->item_type);
      char shield[] = "shield";
      char buf[MIL];
      
      if (obj->item_type  == ITEM_WEAPON)
	name = weapon_name(obj->value[0]);
      else if (obj->item_type  == ITEM_ARMOR){
	if (CAN_WEAR(obj, ITEM_WEAR_SHIELD))
	  name = shield;
      }

      /* name */
      sprintf(buf, "copper %s", name);
      free_string(obj->name);
      obj->name = str_dup(buf);
      
      /* short */
      sprintf(buf, "a copper %s", name);
      free_string(obj->short_descr);
      obj->short_descr = str_dup(buf);
      
      /* long */
      sprintf(buf, "A copper %s is here", name);
      free_string(obj->description);
      obj->description = str_dup(buf);
      
      /* material */
      sprintf(buf, "copper");
      free_string(obj->material);
      obj->material = str_dup(buf);
    }
  }
}