/
roa/
roa/lib/boards/
roa/lib/config/
roa/lib/edits/
roa/lib/help/
roa/lib/misc/
roa/lib/plrobjs/
roa/lib/quests/
roa/lib/socials/
roa/lib/www/
roa/lib/www/LEDSign/
roa/lib/www/LEDSign/fonts/
roa/lib/www/LEDSign/scripts/
roa/src/s_inc/
roa/src/sclient/
roa/src/sclient/binary/
roa/src/sclient/text/
roa/src/util/
/************************************************************************
	Realms of Aurealis 		James Rhone aka Vall of RoA

affect.c			Code dealing with player/object affection
				tracking, removal, adding, updating, etc.

		******** Heavily modified and expanded ********
		*** BE AWARE OF ALL RIGHTS AND RESERVATIONS ***
		******** Heavily modified and expanded ********
		        All rights reserved henceforth. 

    Please note that no guarantees are associated with any code from
Realms of Aurealis.  All code which has been released to the general
public has been done so with an 'as is' pretense.  RoA is based on both
Diku and CircleMUD and ALL licenses from both *MUST* be adhered to as well
as the RoA license.   *** Read, Learn, Understand, Improve ***
*************************************************************************/
#include "conf.h"
#include "sysdep.h"

#include "structures.h"
#include "utils.h"
#include "comm.h"
#include "db.h"
#include "affect.h"
#include "interpreter.h"
#include "acmd.h"
#include "mudlimits.h"
#include "magic.h"
#include "shaman.h"
#include "nature.h"
#include "global.h"
#include "darkenelf.h"

// Initializes affect parameters. 04/18/98 -callahan
void NewAffect(AffType *af)
{
  af->type = 0;
  af->bitvector = 0;
  af->bitvector2 = 0;
  af->modifier = 0;
  af->location = APPLY_NONE;
}

/* set or remove AFF and AFF2 flags on char */
/* spelleq BITVECTORS sent here have no MOD or LOCATION! */
/* only objects with non spelleq affects will */
/* modify stats based on affect modifier and location */
void affect_modify(chdata *ch, byte loc, sbyte mod, long bitv, long bitv2, BOOL add) 
{
  if (add) 
  {
    if (bitv)
      SET_BIT(AFF_FLAGS(ch), bitv);
    if (bitv2)
      SET_BIT(AFF2_FLAGS(ch), bitv2);
  } 
  else 
  {
    if (bitv)
      REMOVE_BIT(AFF_FLAGS(ch), bitv);
    if (bitv2)
      REMOVE_BIT(AFF2_FLAGS(ch), bitv2);
    mod = -mod;
  }

  switch (loc) 
  {
   case APPLY_NONE: break;
   case APPLY_STR: GET_STR(ch) += mod; break;
   case APPLY_DEX: GET_DEX(ch) += mod; break;
   case APPLY_INT: GET_INT(ch) += mod; break;
   case APPLY_WIS: GET_WIS(ch) += mod; break;
   case APPLY_CON: GET_CON(ch) += mod; break;

   case APPLY_AGE:
      ch->player.time.birth -= (mod * SECS_PER_MUD_YEAR);
      break;

   case APPLY_CHAR_WEIGHT:
      GET_WEIGHT(ch) += mod;
      break;

   case APPLY_CHAR_HEIGHT:
      GET_HEIGHT(ch) += mod;
      break;

   case APPLY_MANA:
      ch->points.max_mana += mod;
      break;

   case APPLY_HIT:
      ch->points.max_hit += mod;
      break;

   case APPLY_MOVE:
      ch->points.max_move += mod;
      break;

   case APPLY_AC:
      GET_AC(ch) += mod;
      break;

   case APPLY_HITROLL:
      GET_HITROLL(ch) += mod;
      break;

   case APPLY_DAMROLL:
      GET_DAMROLL(ch) += mod;
      break;

   case APPLY_SV_HEAT:
      SAVING_THROW(ch, SV_HEAT) += mod;
      break;

   case APPLY_SV_COLD:
      SAVING_THROW(ch, SV_COLD) += mod;
      break;

   case APPLY_SV_MAGIC:
      SAVING_THROW(ch, SV_MAGIC) += mod;
      break;

   case APPLY_SV_POISON:
      SAVING_THROW(ch, SV_POISON) += mod;
      break;

   case APPLY_SV_BREATH:
      SAVING_THROW(ch, SV_BREATH) += mod;
      break;

   case APPLY_HIT_REGEN:
      ch->specials.hit_regen += mod;
      break;

   case APPLY_MANA_REGEN:
      ch->specials.mana_regen += mod;
      break;

   case APPLY_MOVE_REGEN:
      ch->specials.move_regen += mod;
      break;

   case APPLY_RITUALS:
      if (IS_SHAMAN(ch))
        RITES(ch) += mod;
      break;

   case APPLY_SEX:
   case APPLY_CLASS:
   case APPLY_LEVEL:
   case APPLY_GOLD:
   case APPLY_EXP:
      break;

   default:
      sprintf(buf, "SYSERR: Unknown adj attempt (%s %d) (affect_modify).", 
	      GET_NAME(ch), loc);
      mudlog(buf, BRF, LEV_IMM, TRUE);
      break;
   } /* switch */
}

/* This updates a character by subtracting everything he is affected by */
/* restoring original abilities, and then affecting all again           */
void	affect_total(chdata *ch)
{
  AffType *af;
  int	i, j;

  for (i = 0; i < MAX_WEAR; i++) 
    if (EQ(ch, i))
      for (j = 0; j < MAX_OBJ_AFFECT; j++)
	affect_modify(ch, EQ(ch, i)->affected[j].location,
		      EQ(ch, i)->affected[j].modifier,
		      EQ(ch, i)->eqaffbit,
		      EQ(ch, i)->eqaff2bit, FALSE);

  for (af = ch->affected; af; af = af->next)
    affect_modify(ch, af->location, af->modifier, af->bitvector, 
                  af->bitvector2, FALSE);

  ch->aff_abils = ch->real_abils;

  for (i = 0; i < MAX_WEAR; i++) 
    if (EQ(ch, i))
      for (j = 0; j < MAX_OBJ_AFFECT; j++)
	affect_modify(ch, EQ(ch, i)->affected[j].location,
		      EQ(ch, i)->affected[j].modifier,
		      EQ(ch, i)->eqaffbit,
		      EQ(ch, i)->eqaff2bit, TRUE);

  for (af = ch->affected; af; af = af->next)
    affect_modify(ch, af->location, af->modifier, 
                  af->bitvector, af->bitvector2, TRUE);

  // IMPs and NPC's max stats 18 (str 18/100)
  i = ((IS_NPC(ch) || GET_LEVEL(ch) == LEV_IMPL) ? 25 : 18);

  GET_DEX(ch) = MAX(0, MIN(GET_DEX(ch), i));
  GET_INT(ch) = MAX(0, MIN(GET_INT(ch), i));
  GET_WIS(ch) = MAX(0, MIN(GET_WIS(ch), i));
  GET_CON(ch) = MAX(0, MIN(GET_CON(ch), i));
  GET_STR(ch) = MAX(0, GET_STR(ch));

  if (IS_NPC(ch)) {
    GET_STR(ch) = MIN(GET_STR(ch), i);
  } else {
    if (GET_STR(ch) > 18) {
      i = GET_ADD(ch) + ((GET_STR(ch) - 18) * 10);
      GET_ADD(ch) = MIN(i, 100);
      GET_STR(ch) = 18;
    }
  }
}

/* Insert an affect_type in a char_data structure
   sets apropriate bits and apply's */
void affect_to_char(chdata *ch, AffType *af)
{
  AffType *affected_alloc;

  CREATE(affected_alloc, AffType, 1);

  *affected_alloc = *af;
  affected_alloc->next = ch->affected;
  ch->affected = affected_alloc;

  affect_modify(ch, af->location, af->modifier, af->bitvector, 
                af->bitvector2, TRUE);
  affect_total(ch);
}

// for those annoyingly special affects...
void remove_affect_specials(chdata *ch, AffType *af)
{
  void unbecome(chdata *ch);

  switch(af->type) {
    case SPELL_ANIMATE_DEAD:
      if (IS_PC(ch) && ch->followers)
        send_to_char("Your undead followers are now fully animated.\r\n", ch);
      break;

    case SPELL_HOLD_PERSON:  // no longer has a holder if the affect wore off
      HOLDER(ch) = NULL;
      break;

    case SPELL_SLEEP:  // wake up when sleep wears off...
      do_wake(ch, "", 0, 0);
      break;

    case SKILL_BECOME:
      unbecome(ch);
      break;

    case SKILL_PRESENCE:
      if (ch->desc && ch->desc->room_snooping && !INVALID_ROOM(ch->desc->room_snooping))
        remove_room_snooper(&world[ch->desc->room_snooping], ch->desc);
      break;

    default:
      break;
  }
}

/* Remove an affected_type structure from a char (called when duration
   reaches zero). Pointer *af must never be NULL! Frees mem and calls 
   affect_location_apply                                                */
void affect_remove(chdata *ch, AffType *af)
{
  AffType *temp;

  assert(ch->affected);

  remove_affect_specials(ch, af);

  affect_modify(ch, af->location, af->modifier, 
		af->bitvector,af->bitvector2, FALSE);

  REMOVE_FROM_LIST(af, ch->affected, next);
  FREENULL(af);

  affect_total(ch);
}

/* Call affect_remove with every spell of spelltype "skill" */
void	affect_from_char(chdata *ch, int skill)
{
  AffType *aff, *nxt;  /* <-- use nxt ptr to one !! */

  for (aff = ch->affected; aff; aff = nxt)
  {
    nxt = aff->next;
    if (aff->type == skill)
      affect_remove(ch, aff);
  }
}

// is this char affected by this skill/spell
BOOL affected_by_spell(chdata *ch, int skill)
{
  AffType *aff;

  for (aff = ch->affected; aff; aff = aff->next)
    if (aff->type == skill)
      return(TRUE);
  return(FALSE);
}

// instead of adding a new affect, join this affect with one that
// already exists on the character, if there is one that is
// this will basically 'boost' up the duration
void affect_join(chdata *ch, AffType *af, BOOL avg_dur, BOOL avg_mod)
{
  AffType *aff, *nxt; 
  BOOL found = FALSE;

  for (aff = ch->affected; !found && aff; aff = nxt) 
  {
    nxt = aff->next;
    if ( aff->type == af->type ) 
    {
      af->duration += aff->duration;
      if (avg_dur)
        af->duration /= 2;

      af->modifier += aff->modifier;
      if (avg_mod)
        af->modifier /= 2;

      affect_remove(ch, aff);
      affect_to_char(ch, af);
      found = TRUE;
    }
  }

  // if it didnt join anything, add it normal
  if (!found)
    affect_to_char(ch, af);
}

/* Return the affect of a piece of armor in position eq_pos */
int	apply_ac(chdata *ch, int eq_pos)
{
  int factor;

  assert(EQ(ch, eq_pos));

  if (!IS_ARMOR(EQ(ch, eq_pos)))
    return 0;

  switch (eq_pos) 
  {
    case W_BODY	: factor = 3; break;	/* 30% */
    case W_HEAD	: factor = 2; break;	/* 20% */
    case W_LEGS	: factor = 2; break;	/* 20% */
    default	: factor = 1; break;	/* all others 10% */
  }

  return (factor * EQ(ch, eq_pos)->value[0]);
}

/* This function sends the appropriate messages for SPELL_EQ */
void send_aff1_mesg(chdata *ch, int j, BOOL flag)
{
  if (flag == TRUE) 
  {
    switch (j) 
    {
      case AFF_BLIND:
        act("$n seems to be blinded!", TRUE, ch, 0, 0, TO_ROOM);
        send_to_char("You have been blinded!\r\n", ch);
        break;
      case AFF_INVISIBLE:
        send_to_char("You vanish.\r\n", ch);
        act("$n slowly fades out of existence.", FALSE, ch, 0, 0, TO_ROOM);
        break;
      case AFF_DETECT_EVIL:
        send_to_char("You are now able to perceive evil in others.\r\n", ch);
        break; 
      case AFF_DETECT_ALIGN:
        send_to_char("You can now distinguish good from evil.\r\n", ch);
        break; 
      case AFF_DETECT_INVISIBLE:
        send_to_char("Your eyes tingle.\r\n", ch);
        break;
      case AFF_DETECT_MAGIC:
        send_to_char("Your can now detect magical items and monsters.\r\n", ch);
        break;
      case AFF_SENSE_LIFE:
        send_to_char("You feel your awareness improve.\r\n", ch);
        break;
      case AFF_GILLS:
        send_to_char("You feel as if you can breathe underwater.\r\n", ch);
        break; 
      case AFF_WINGS:
        send_to_char("You feel as if you can soar through the sky.\r\n", ch);
        break; 
      case AFF_CURSE:
        send_to_char("You feel very unholy...\r\n", ch);
        act("Suddenly, a black unholy aura surrounds $n.", TRUE, ch, 0, 0, TO_ROOM);
        break;
      case AFF_INFRARED:
        send_to_char("Your eyes glow red.\r\n", ch);
        act("$n's eyes glow red.", TRUE, ch, 0, 0, TO_ROOM);
        break;
      case AFF_POISON:
        send_to_char("You become much weaker as poison needles on your clothes enter your blood.\r\n", ch);
        act("As poisoned needles enter $n's blood, $e shivers and suffers.", TRUE, ch, 0, 0, TO_ROOM);
        break;
      case AFF_PROTECT_EVIL:
        send_to_char("A holy aura falls upon you!\r\n", ch);
        break;
      case AFF_PROTECT_GOOD:
        send_to_char("An evil aura falls upon you!\r\n", ch);
        break; 
      case AFF_SANCTUARY:
        act("$n is surrounded by a white aura.", TRUE, ch, 0, 0, TO_ROOM);
        act("You start glowing.", TRUE, ch, 0, 0, TO_CHAR);
        break;
      case AFF_SNEAK:
        act("You now walk very quietly.", TRUE, ch, 0, 0, TO_CHAR);
        break;
      case AFF_HIDE:
        act("You are now hidden to the outside world.", TRUE, ch, 0, 0, TO_CHAR);
        break;
      case AFF_HASTE:
        act("Your body starts to sizzle with energy.", TRUE, ch, 0, 0, TO_CHAR);
        act("$n's body starts to sizzle with energy.", TRUE, ch, 0, 0, TO_ROOM);
        break;
      case AFF_HOLD:
        act("You are unable to move!", TRUE, ch, 0, 0, TO_CHAR);
        break;
      default:
        break;
    }
  }
  else 
  {
    switch (j) 
    {
      case AFF_BLIND:
        act("$n can see again.", TRUE, ch, 0, 0, TO_ROOM);
        send_to_char("Your vision returns!\r\n", ch);
        break;
      case AFF_INVISIBLE:
        send_to_char("You are no longer invisible.\r\n", ch);
        act("$n slowly fades into existence.", TRUE, ch, 0, 0, TO_ROOM);
        break;
      case AFF_DETECT_EVIL:
        send_to_char("You are no longer able to perceive evil in others.\r\n", ch);
        break; 
      case AFF_DETECT_ALIGN:
        send_to_char("You can no longer distinguish good from evil.\r\n", ch);
        break; 
      case AFF_DETECT_INVISIBLE:
        send_to_char("Your eyes stop tingling.\r\n", ch);
        break;
      case AFF_DETECT_MAGIC:
        send_to_char("Your can no longer detect magical items and monsters.\r\n", ch);
        break;
      case AFF_SENSE_LIFE:
        send_to_char("You are no longer aware of hidden creatures.\r\n", ch);
        break;
      case AFF_GILLS:
        send_to_char("You can no longer breathe underwater.\r\n", ch);
        break; 
      case AFF_WINGS:
        send_to_char("You can no longer soar through the sky.\r\n", ch);
        break; 
      case AFF_CURSE:
        send_to_char("You no longer feel so unholy...\r\n", ch);
        act("The black unholy aura surrounding $n vanishes.", TRUE, ch, 0, 0, TO_ROOM);
        break;
      case AFF_INFRARED:
        send_to_char("Your eyes stop glowing red.\r\n", ch);
        act("$n's eyes stop glowing red.", TRUE, ch, 0, 0, TO_ROOM);
        break;
      case AFF_POISON:
        send_to_char("You relax a little as none of your clothing is no longer poisoned.\r\n", ch);
        act("$n relaxes a little as $e takes off poisoned clothes.", TRUE, ch, 0, 0, TO_ROOM);
        break;
      case AFF_PROTECT_EVIL:
        send_to_char("You feel vulnerbale to evil!\r\n", ch);
        break;
      case AFF_PROTECT_GOOD:
        send_to_char("You feel vulnerable to goodness!\r\n", ch);
        break; 
      case AFF_SANCTUARY:
        act("The white aura around $n's body vanishes.", TRUE, ch, 0, 0, TO_ROOM);
        act("You stop glowing.", TRUE, ch, 0, 0, TO_CHAR);
        break;
      case AFF_SNEAK:
        act("You sure are noisy.", TRUE, ch, 0, 0, TO_CHAR);
        act("You suddenly notice how noisy $n is.", TRUE, ch, 0, 0, TO_ROOM);
        break;
      case AFF_HIDE:
        act("You are no longer hidden.", TRUE, ch, 0, 0, TO_CHAR);
        act("$n is no longer hiding.", TRUE, ch, 0, 0, TO_ROOM);
        break;
      case AFF_HASTE:
        act("Your body is no longer sizzling with energy.", TRUE, ch, 0, 0, TO_CHAR);
        act("$n's body is no longer sizzling with energy.", TRUE, ch, 0, 0, TO_ROOM);
        break;
      case AFF_HOLD:
        act("You are able to move again!", TRUE, ch, 0, 0, TO_CHAR);
        break;
      default:
        break;
    }
  }
}

/* This function sends the appropriate messages for SPELL_EQ */
void send_aff2_mesg(chdata *ch, int j, BOOL flag)
{
  if (flag == TRUE) 
  {
    switch (j) 
    {
      case AFF2_CLAWS:
        act("Your hands meld into %3claws%0!!", TRUE, ch, 0, 0, TO_CHAR);
        act("$n's hands meld into %3claws%0!!", TRUE, ch, 0, 0, TO_ROOM);
	break;
      case AFF2_CROW:
        act("You feel the %Bcrow%0 spirit with you!!", TRUE, ch, 0, 0, TO_CHAR);
        act("$n is filled with the power of the %Bcrow%0!!", TRUE, ch, 0, 0, TO_ROOM);
	break;
      case AFF2_WOLF:
        act("You feel the %Bwolf%0 spirit with you!!", TRUE, ch, 0, 0, TO_CHAR);
        act("$n is filled with the power of the %Bwolf%0!!", TRUE, ch, 0, 0, TO_ROOM);
	break;
      case AFF2_LIGHT:
        world[ch->in_room].light++;
        act("A %6soft glow of bluish light%0 surrounds you.", TRUE, ch, 0, 0, TO_CHAR);
        act("A %6soft glow of bluish light%0 surrounds $n.", TRUE, ch, 0, 0, TO_ROOM);
	break;
      case AFF2_STONE_SKIN:
        act("You are covered with skin of stone!", TRUE, ch, 0, 0, TO_CHAR);
        act("A skin of stone covers $n!", TRUE, ch, 0, 0, TO_ROOM);
	break;
      case AFF2_CALM:
        act("Your mind is overcome with a sense of peace.", TRUE, ch, 0, 0, TO_CHAR);
        act("$n suddenly looks very peaceful.", TRUE, ch, 0, 0, TO_ROOM);
	break;
      case AFF2_ILLUMINATE:
        act("A %3%Bbright glow of golden light%0 surrounds you.", TRUE, ch, 0, 0, TO_CHAR);
        act("A %3%Bbright glow of golden light%0 surrounds $n.", TRUE, ch, 0, 0, TO_ROOM);
	break;
      default:
        break;
    }
  }
  else 
  {
    switch (j) 
    {
      case AFF2_CLAWS:
        act("Your hands return to normal.", TRUE, ch, 0, 0, TO_CHAR);
        act("$n's hands return to normal.", TRUE, ch, 0, 0, TO_ROOM);
	break;
      case AFF2_CROW:
        act("You feel the %Bcrow%0 spirit leave you!!", TRUE, ch, 0, 0, TO_CHAR);
        act("$n winces as the %Bcrow%0 spirit leaves $m.", TRUE, ch, 0, 0, TO_ROOM);
	break;
      case AFF2_WOLF:
        act("You feel the %Bwolf%0 spirit leave you!!", TRUE, ch, 0, 0, TO_CHAR);
        act("$n winces as the %Bwolf%0 spirit leaves $m.", TRUE, ch, 0, 0, TO_ROOM);
	break;
      case AFF2_LIGHT:
        act("The %6bluish light%0 surrounding you vanishes.", TRUE, ch, 0, 0, TO_CHAR);
        act("The %6bluish light%0 surrounding $n vanishes.", TRUE, ch, 0, 0, TO_ROOM);
        world[ch->in_room].light--;
        world[ch->in_room].light = MAX(0, world[ch->in_room].light);
	break;
      case AFF2_STONE_SKIN:
        act("Your skin returns to normal.", TRUE, ch, 0, 0, TO_CHAR);
        act("$n's skin returns to normal.", TRUE, ch, 0, 0, TO_ROOM);
	break;
      case AFF2_CALM:
        act("Your mind is overcome with a sense of violence.", TRUE, ch, 0, 0, TO_CHAR);
        act("$n suddenly looks less peaceful.", TRUE, ch, 0, 0, TO_ROOM);
	break;
      case AFF2_ILLUMINATE:
        act("The %3%Bgolden light%0 surrounding you vanishes.", TRUE, ch, 0, 0, TO_CHAR);
        act("The %3%Bgolden light%0 surrounding $n vanishes.", TRUE, ch, 0, 0, TO_ROOM);
	break;
      default:
        break;
    }
  }
}

int decrement_affect(chdata *ch, int spell)
{
  AffType *af, *next_af;
  for (af = ch->affected; af; af = next_af)
  {
    next_af = af->next;
    if (af->type == spell)
    {
      if (--(af->duration) <= 0)
      {
        affect_remove(ch, af);
        return AFFECT_REMOVED;
      }
      return AFFECT_DECREMENTED;
    }
  }
  return AFFECT_NOTFOUND;
}

// called for each char per each round of combat for those special spell
// affects that decrement per round... (eg. BLINDSTRIKE)  4/18/98 -jtrhone
void check_per_round_affects(chdata *ch)
{
  decrement_affect(ch, SKILL_BLINDSTRIKE);
}

// every few pulses, update everybody's affects
void	affect_update( void )
{
  struct affected_type *af, *next_af;
  chdata *ch, *next_ch;

  for (ch = character_list; ch; ch = next_ch)
  {
    next_ch = ch->next;
    for (af = ch->affected; af; af = next_af) 
    {
	 next_af = af->next;
	 if (af->duration >= 1)
         {
	    /* warn player of impending danger RoA*/
            if (af->type == SPELL_WINGS && af->duration <= 2)
		send_to_char("You're losing your wings!\n\r",ch);

            if (af->type == SPELL_GILLS && af->duration <= 2)
		send_to_char("You're losing your gills!\n\r",ch);

	    af->duration--;
         }
	 else 
	 if (af->duration == -1)
	    af->duration = -1;  /* GODs only! unlimited */
	 else 
	 {
	    if ((af->type > 0) && (af->type < MAX_SPELLS))
	       if (!af->next || (af->next->type != af->type) || (af->next->duration > 0))
		  if (spell_info[af->type].wear_off)
		  {
		     send_to_char(spell_info[af->type].wear_off, ch);
		     send_to_char("\n\r", ch);
		  }

	    affect_remove(ch, af);
	    float_sink_char(ch);
	 }
    }
  }
}