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    *
 ***************************************************************************/

/*Written by Virigoth sometime circa april 2000 for CURSED LANDS mud.*/
/* NOT TO BE USED WITHOUT EXPLICIT PERMISSION OF AUTHOR */
/*This is the implementation of the AVATAR sub race */
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"
#include "magic.h"
#include "recycle.h"
#include "interp.h"


const struct avatar_type  avatar_info [MAX_AVATAR] = 
{
  /* Level 0, automatic +1 to all stats, glowing body */
  {0, 0, {NULL, NULL, NULL, NULL}, "You have been blessed with $g's power."  },

  /* Level 1, call: sight, infrared */
  {500, AFF_INFRARED, {"sight", NULL, NULL, NULL}, "$g's power fills your soul."  },    

  /* Level 2, call: imm to corruption */
  {1500, 0, {"sight", NULL, NULL, NULL}, "$g's spirit courses through your veins."},


  /* Level 3, automatic resotre faith, call temple */
  {2500, 0, {"sight", "temple", NULL, NULL}, "You are $n the Righteous Wrath of $g."},    

  /* Level 4, call: purify and protection*/
  {3500, AFF_PROTECT_EVIL, {"sight", "temple", "purify", NULL}, "You are $n the Holy Vengence of $g."},    

  /* Level 5, flight */
  {4500, AFF_FLYING,{"sight", "temple", "purify", NULL}, "You are $n, $g's Holy Retribution."},    

  /* Level 6, call: empower */
  {5500, 0, {"sight", "temple", "purify", "empower"}, "You are an Avatar, the Divine Messenger of $g."}
};


/* Written by: Virigoth */
/* returns: NULL*/
/* Used in: update_avatar */
/* Comments:  sets efects that update_Avatar might have removed */

void avatar_affect_check(CHAR_DATA *ch,int where,int vector)
{
    AFFECT_DATA *paf;
    OBJ_DATA *obj;

    ch->affected_by = ch->affected_by|race_table[ch->race].aff;
    for (paf = ch->affected; paf != NULL; paf = paf->next)
	if (paf->where == where && paf->bitvector == vector)
	{
	    switch (where)
	    {
                case TO_AFFECTS:  SET_BIT(ch->affected_by,vector);  break;
                case TO_AFFECTS2: SET_BIT(ch->affected2_by,vector); break;
                case TO_IMMUNE:   SET_BIT(ch->imm_flags,vector);    break;
                case TO_RESIST:   SET_BIT(ch->res_flags,vector);    break;
                case TO_VULN:     SET_BIT(ch->vuln_flags,vector);   break;
	    }
	    return;
        }
    for (paf = ch->affected2; paf != NULL; paf = paf->next)
	if (paf->where == where && paf->bitvector == vector)
	{
	    switch (where)
	    {
                case TO_AFFECTS:  SET_BIT(ch->affected_by,vector);  break;
                case TO_AFFECTS2: SET_BIT(ch->affected2_by,vector); break;
                case TO_IMMUNE:   SET_BIT(ch->imm_flags,vector);    break;
                case TO_RESIST:   SET_BIT(ch->res_flags,vector);    break;
                case TO_VULN:     SET_BIT(ch->vuln_flags,vector);   break;
	    }
	    return;
        }
    for (obj = ch->carrying; obj != NULL; obj = obj->next_content)
    {
	if (obj->wear_loc == -1)
	    continue;
        for (paf = obj->affected; paf != NULL; paf = paf->next)
            if (paf->where == where && paf->bitvector == vector)
            {
                switch (where)
                {
                    case TO_AFFECTS:  SET_BIT(ch->affected_by,vector);  break;
                    case TO_AFFECTS2: SET_BIT(ch->affected2_by,vector); break;
                    case TO_IMMUNE:   SET_BIT(ch->imm_flags,vector);    break;
                    case TO_RESIST:   SET_BIT(ch->res_flags,vector);    break;
                    case TO_VULN:     SET_BIT(ch->vuln_flags,vector);   break;
                }
                return;
            }
        if (obj->enchanted)
	    continue;
        for (paf = obj->pIndexData->affected; paf != NULL; paf = paf->next)
            if (paf->where == where && paf->bitvector == vector)
            {
                switch (where)
                {
                    case TO_AFFECTS:  SET_BIT(ch->affected_by,vector);  break;
                    case TO_AFFECTS2: SET_BIT(ch->affected2_by,vector); break;
                    case TO_IMMUNE:   SET_BIT(ch->imm_flags,vector);    break;
                    case TO_RESIST:   SET_BIT(ch->res_flags,vector);    break;
                    case TO_VULN:     SET_BIT(ch->vuln_flags,vector);   break;
                }
                return;
            }
    }

}

/* Written by: Virigoth */
/* returns: Level of AVATAR */
/* Used in: many avatar orientated functions */
/* Comments:  uses the avatar_info table to find level. */
int get_avatar_level(CHAR_DATA* ch){
  int level = 0;

  if (!ch){
    bug("NULL character passed to: get_avatar_level",0);
    return 0;
  }

  if (IS_NPC(ch))
    return 0;

  for(level = 0; level < MAX_AVATAR; level++){
    if (ch->pcdata->divfavor < avatar_info[level].min_favor)
      return UMAX(0, level - 1);
  }

  return MAX_AVATAR - 1;
}

/* Written by: Virigoth */
/* returns: VOID */
/* Used in: avatar.c handler.c*/
/* Comments:  uses the avatar_info table to find the flags to be applied
   the boolean fRem specifies if flags should be removed instead of added. 
   NOTE:This is also used in affect_check of handler.c
*/

void update_avatar(CHAR_DATA* ch, bool fRem){
  AFFECT_DATA af;

  int level = 0;
  int cur_level = 0;

  if (!ch){
    bug("NULL character passed to: updateavatar",0);
    return;
  }
  if (IS_NPC(ch)){
    bug("NPC passed to: update_avatar", 0);
    return;
  }
  cur_level = get_avatar_level(ch);

  /* dummy affect so we can apply flags properly */
  af.type = 0;
  af.duration = -1;
  af.level = ch->level;
  af.location = APPLY_NONE;
  af.modifier = 0;

  af.where = TO_AFFECTS;
  af.bitvector = 0;

  /* we run through levels setting bits or removing them depending on the flag and level */
  for (level =0; level < MAX_AVATAR; level++){
    af.bitvector =  avatar_info[level].flags;
    if ( (fRem || level > cur_level) && af.bitvector){
      affect_modify(ch, &af, FALSE);
      /* check if we removed something that should stay. */
      avatar_affect_check(ch, af.where, af.bitvector);
    }
    else if ( (level <= cur_level) && af.bitvector)
      affect_modify(ch, &af, TRUE);
  }


}

/* Written by: Virigoth */
/* returns: returns string describing level of avatar*/
/* Used in: act_wiz.c act_info.c */
/* Comments:  uses the avatar_info table to find level/string. */
char* get_avatar_desc(CHAR_DATA* ch){

  if (!ch){
    bug("NULL character passed to: get_avatar_desc",0);
    return str_empty;
  }
  if (IS_NPC(ch)){
    bug("NPC passed to: get_avatar_desc", 0);
    return str_empty;
  }

  return avatar_info[get_avatar_level(ch)].desc;
}


/* Written by: Virigoth */
/* returns: VOID */
/* Used in: fight.c, update.c, skills5.c  (any time divinefavor is changed) */
/* Comments:  Changes divine favor total on character, showing appropriate messages */
void divfavor_gain(CHAR_DATA* ch, int gain){

  const int max_avatar = 6000;//maximum at which any gain can occur
  const int abs_max_avatar = 7500;//absolute maximum for divine favor of avatar

  if (!ch || gain == 0){
    bug("Null character or 0 gain passed to: divfavor_gain", 0);
    return;
  }

  if (IS_NPC(ch)){
    bug("NPC character passed to: divfavor_gain", 0);
    return;
  }

  /* show message (only if a significant amount is gained)*/
  if (abs(gain) > 5){
    if (gain > 0)
      act("You sense your favor with $g increase.", ch, NULL, NULL, TO_CHAR);
    else
      act("You sense your favor with $g decrease.", ch, NULL, NULL, TO_CHAR);
  }


  /* We handle each race/class using divine favor seperatly */

/* AVATAR */
  if (IS_AVATAR(ch)){
    int pre_lvl = get_avatar_level(ch);
    int post_lvl = 0;
    /* avatars only increase if not at 6500, to maximum of 7500 */
    if (ch->pcdata->divfavor <= max_avatar || gain < 0)
      ch->pcdata->divfavor = URANGE(0, ch->pcdata->divfavor + gain, abs_max_avatar);
    update_avatar(ch, FALSE);
    post_lvl = get_avatar_level(ch);
    /* show messages about levels. */
    if (post_lvl > pre_lvl)
      act("You feel $g's spirit empower your soul as you achive new level of righteous power.", ch, NULL, NULL, TO_CHAR);
    else if (post_lvl < pre_lvl)
      act("You feel a part of $g's blessing leave your soul.", ch, NULL, NULL, TO_CHAR);
  }

}


/* Written by: Virigoth */
/* returns: VOID */
/* Used in: fight.c */
/* Comments:  Handles gain/loss of divine favor on PC kill. */
void divfavor_update(CHAR_DATA* ch, CHAR_DATA* victim){
  CHAR_DATA* ava = ch;
  if (!ch || !victim){
    bug("NULL argument passed to: divfavor_update", 0);
    return;
  }

  /* NPC's dont do anything */
  if ((IS_NPC(ch) && !IS_AFFECTED(ch, AFF_CHARM) && !ch->master)
      || IS_NPC(victim))
    return;

  /* Handle each case */

/* VICTIM */
  /* AVATAR */
  if (IS_AVATAR(victim))
      divfavor_gain(victim, DIVFAVOR_LOSS);


  /* if kill was made by charmie we substitue the master */
  if (IS_NPC(ch) && IS_AFFECTED(ch, AFF_CHARM)
      && ch->master)
    ava = ch->master;

/* CHARACTER */
  /* AVATAR */
  if (IS_AVATAR(ava)){
    /* penalties first */
    if (IS_GOOD(ava) && IS_GOOD(victim))
      divfavor_gain(ava, -ava->pcdata->divfavor);
    else if (IS_GOOD(ava) && IS_NEUTRAL(victim))
      divfavor_gain(ava, DIVFAVOR_LOSS);
    else if (IS_EVIL(ava) && IS_NEUTRAL(victim))
      divfavor_gain(ava, DIVFAVOR_LOSS);
    else if (IS_EVIL(ava) && IS_EVIL(victim))
      divfavor_gain(ava, -ava->pcdata->divfavor);

    /* Now benefits */
    if ( (IS_GOOD(ava) && IS_EVIL(victim))
	 || (IS_EVIL(ava) && IS_GOOD(victim)) ){
      /* Healers get 4x on undead only*/
      if (ava->class == class_lookup("healer")){
	if (IS_UNDEAD(victim))
	  divfavor_gain(ava, 4 * DIVFAVOR_GAIN);
	else
	  divfavor_gain(ava, DIVFAVOR_GAIN);
      }//END HEALER

      /* Normal avatars get 3x on demons */
      else if (IS_DEMON(victim))
	divfavor_gain(ava, 3 * DIVFAVOR_GAIN);
      else
	divfavor_gain(ava, DIVFAVOR_GAIN);
    }
   }//END AVATAR
}

/* Written by: Virigoth */
/* returns: VOID */
/* Used in: update.c */
/* Comments:  Handles special tick udpates for avatars */
void avatar_tick(CHAR_DATA* ch){
  const int level = ch->level;
  const int restore_faith = URANGE(5, 2 * (level - 20) + get_avatar_level(ch) * 5, 90);

  const int res_cost = 125;

  /* check if faith should be restored */
  if (is_affected(ch, gsn_blasphemy) && number_percent() < restore_faith){
    act("The strength of $g's spirit floods your body and your faith renews itself.", ch, NULL, NULL, TO_CHAR);
    act("An aura of $g's power briefly surrounds $n.", ch, NULL, NULL, TO_ROOM);
    divfavor_gain(ch,  -res_cost);
    affect_strip(ch, gsn_blasphemy);
  }
}