idirt-1.82d/
idirt-1.82d/bin/
idirt-1.82d/data/LOGS/
idirt-1.82d/data/POLICY/
idirt-1.82d/data/WIZ_ZONES/
idirt-1.82d/doc/
idirt-1.82d/doc/info/
idirt-1.82d/doc/manual/
idirt-1.82d/src/Ident/
idirt-1.82d/src/utils/
idirt-1.82d/utils/
#include <stdlib.h>
#include "kernel.h"
#include "oflags.h"
#include "eflags.h"
#include "pflags.h"
#include "lflags.h"
#include "sendsys.h"
#include "verbs.h"
#include "mobiles.h"
#include "objects.h"
#include "locations.h"
#include "objsys.h"
#include "spell.h"
#include "spells.h"
#include "bprintf.h"
#include "parse.h"
#include "fight.h"
#include "mobile.h"
#include "sflags.h"

void
spellscom (void)
{
  struct SPELL *spell;
  char dam[4], type[9];

  bprintf ("You know the following spells:\n");
  bprintf ("&+B---------------------------------------------------------------\n");
  bprintf ("&+WCommand    Spell                Mana  Damage  Chance  Type\n");
  bprintf ("&+B---------------------------------------------------------------\n");
  for (spell = spell_table; spell->verb >= 0; spell++) {
    if (etstflg (mynum, spell->flag)) {
      sprintf (dam, "%d", spell->damage);
      sprintf (type, "%s", spell->type == ATTACK ? "Attack" :
	       spell->type == HEAL ? "Heal" :
	       spell->duration ? "Duration" : "Special");
      bprintf ("&*%-10.10s %-20.20s %4d  %6.6s  %6d  %-9.9s\n",
	       spell->verbname, spell->name, spell->mana,
	       spell->damage ? dam : "---", spell->chance, type);
    }
  }
  bprintf ("&+B---------------------------------------------------------------\n");
}

void
spellcom (int spell)
{
  int victim = brkword () < 0 ? pfighting (mynum) : fpbn (wordbuf);

  if (!is_in_game (victim))
    bprintf ("Who?\n");
  else
    cast_spell (mynum, victim, spell);
}

Boolean
cast_spell (int caster, int victim, int verb)
{
  int chance, damage = 0;
  int factor = 1;

  struct SPELL *spell;
  Boolean miss = False;

  /* Find spell */
  for (spell = spell_table; spell->verb != verb; spell++) {
    if (spell->verb < 0)
      return False;		/* No such spell */
  }

  if (victim == pfighting (caster) && spell->type != ATTACK) {
    bprintf ("Who?\n");
    return False;
  }
  /* Check to see if spell can be casted across a distance */
  if (plev (caster) < LVL_WIZARD && ploc (caster) != ploc (victim)) {
    if (spell->type != SPECIAL) {
      sendf (caster, "%s is not here.\n", pname (victim));
      return False;
    }
  }
  /* Check if player knows the spell */
  if (!etstflg (caster, spell->flag)) {
    bprintf ("You have not learned this spell yet.\n");
    return False;
  }
  /* Check if the spell can be cast */
  if (plev (caster) < LVL_WIZARD) {
    if (caster < max_players && pmagic (caster) < spell->mana) {
      sendf (caster, "You are to weak to cast this spell.\n");
      return False;
    }
    if (testpeace (caster) && spell->type == ATTACK) {
      sendf (caster, "No, that's violent!\n");
      return False;
    }
    if (ltstflg (ploc (victim), LFL_NO_MAGIC)) {
      sendf (caster, "Something about this location has drained your mana.\n");
      return False;
    }
    chance = (caster >= max_players) ? 60 + spell->chance : spell->chance;

    if (carries_obj_type (caster, OBJ_BLIZZARD_POWERSTONE) > -1)
      ++chance;
    if (carries_obj_type (caster, OBJ_BLIZZARD_POWERSTONE1) > -1)
      ++chance;
    if (carries_obj_type (caster, OBJ_BLIZZARD_POWERSTONE2) > -1)
      ++chance;
    if (carries_obj_type (caster, OBJ_FANTASY_MANA) > -1)
      chance += 2;

    if (caster < max_players && randperc () > chance + (4 * plev (caster))) {
      miss = True;
    }
    if (ptstflg (victim, PFL_NOHASSLE) != 0 && spell->type == ATTACK) {
      sendf (caster, "Something prevents you from casting your spell.\n");
      return False;
    }
  }
  /* Attack type spell */
  if (spell->type == ATTACK) {
    if (caster == victim) {
      sendf (victim, "You're supposed to be killing others, not yourself.\n");
      return False;
    }
    if (!do_okay (caster, victim, PFL_NOHASSLE)) {
      sendf (caster, "Something prevents you from casting your spell.\n");
      return False;
    }
    if (caster < max_players)
      setpmagic (caster, pmagic (caster) - spell->mana);

    send_magic_msg (caster, caster, victim, spell->spell_msg, CASTER);
    send_magic_msg (victim, caster, victim, spell->spell_msg_vic, VICTIM);
    send_magic_msg (ploc (caster), caster, victim, spell->to_room, ROOM);

    if (miss) {
      send_magic_msg (caster, caster, victim, spell->to_casterm, TOCAST);
      send_magic_msg (victim, caster, victim, spell->to_victimm, TOVIC);
      send_magic_msg (ploc (caster), caster, victim, spell->to_othersm, TOROOM);
      return False;
    }
    if (plev (caster) < LVL_WIZARD &&
#ifdef LOCMIN_TALON
	carries_obj_type (victim, OBJ_TALON_TALONSHIELD) > -1 &&
#endif
	carries_obj_type (victim, OBJ_CATACOMB_SHIELD) > -1) {

      sendf (caster, "The spell is absorbed by %s shield!\n", his_or_her (victim));

      send_msg (ploc (caster), 0, LVL_MIN, LVL_MAX, caster, victim,
		"\001p%s\003 casts a spell on \001p%s\003. It is absorbed by %s shield!\n",
		pname (caster), pname (victim), his_or_her (victim));

      sendf (victim, "%s casts a spell on you. It is absorbed by your shield!\n",
	     see_name (victim, caster));

      return False;
    }
    if (spell->immune_flag != NOFLAG && etstflg (victim, spell->immune_flag)) {
      send_magic_msg (caster, caster, victim, spell->to_casteri, TOCAST);
      send_magic_msg (victim, caster, victim, spell->to_victimi, TOVIC);
      send_magic_msg (ploc (caster), caster, victim, spell->to_othersi, TOROOM);
      return False;
    }
    if (spell->fear_flag != NOFLAG && etstflg (victim, spell->fear_flag))
      factor += 4;

    if (check_object (caster, spell->obj_flag))
      factor += 2;

    send_magic_msg (caster, caster, victim, spell->to_caster, TOCAST);
    send_magic_msg (victim, caster, victim, spell->to_victim, TOVIC);
    send_magic_msg (ploc (caster), caster, victim, spell->to_others, TOROOM);

    if (plev (caster) < LVL_WIZARD)
      damage = spell->damage * factor;
    else
      damage = pstr (victim) + 1;

    wound_player (caster, victim, damage, 0);
  }
  /* Heal type spell */
  if (spell->type == HEAL) {
    if (caster < max_players)
      setpmagic (caster, pmagic (caster) - spell->mana);

    send_magic_msg (caster, caster, victim, spell->spell_msg, CASTER);
    send_magic_msg (victim, caster, victim, spell->spell_msg_vic, VICTIM);
    send_magic_msg (ploc (caster), caster, victim, spell->to_room, ROOM);

    if (miss) {
      send_magic_msg (caster, caster, victim, spell->to_casterm, TOCAST);
      send_magic_msg (victim, caster, victim, spell->to_victimm, TOVIC);
      send_magic_msg (ploc (caster), caster, victim, spell->to_othersm, TOROOM);
      return False;
    }
    if (check_object (caster, spell->obj_flag))
      factor += 2;

    send_magic_msg (caster, caster, victim, spell->to_caster, TOCAST);
    send_magic_msg (victim, caster, victim, spell->to_victim, TOVIC);
    send_magic_msg (ploc (caster), caster, victim, spell->to_others, TOROOM);

    damage = spell->damage * factor;
    setpstr (victim, pstr (victim) + damage);
  }
  /* Special Spell */
  if (spell->type == SPECIAL) {

    /* Check all Special spells that are to the caster's room */
    if (spell->verb == VERB_VTOUCH || spell->verb == VERB_LIT ||
	spell->verb == VERB_DAMAGE || spell->verb == VERB_ARMOR ||
	spell->verb == VERB_BLUR) {
      if (ploc (caster) != ploc (victim)) {
	sendf (caster, "%s is not here.\n", pname (victim));
      }
    }
    if (!do_okay (caster, victim, PFL_NOHASSLE)) {
      sendf (caster, "Something prevents you from casting your spell.\n");
      return False;
    }
    if (spell->verb == VERB_VTOUCH) {
      if (caster == victim) {
	sendf (victim, "It's pointless to suck your own life away!\n");
	return False;
      }
    }
    if (check_duration (victim, spell->verb)) {
      sendf (victim, "%s are already under the effects of that spell.\n",
	     caster == victim ? "You" : "They");
      return False;
    }
    if (caster < max_players)
      setpmagic (caster, pmagic (caster) - spell->mana);

    send_magic_msg (caster, caster, victim, spell->spell_msg, CASTER);
    send_magic_msg (victim, caster, victim, spell->spell_msg_vic, VICTIM);
    send_magic_msg (ploc (caster), caster, victim, spell->to_room, ROOM);

    if (miss) {
      send_magic_msg (caster, caster, victim, spell->to_casterm, TOCAST);
      send_magic_msg (victim, caster, victim, spell->to_victimm, TOVIC);
      send_magic_msg (ploc (caster), caster, victim, spell->to_othersm, TOROOM);
      return False;
    }
    if (plev (mynum) < LVL_WIZARD) {
      if (spell->immune_flag != NOFLAG && etstflg (victim, spell->immune_flag)) {
	send_magic_msg (caster, caster, victim, spell->to_casteri, TOCAST);
	send_magic_msg (victim, caster, victim, spell->to_victimi, TOVIC);
	send_magic_msg (ploc (caster), caster, victim, spell->to_othersi, TOROOM);
	return False;
      }
      if (spell->fear_flag != NOFLAG && etstflg (victim, spell->fear_flag))
	factor += 4;

      if (check_object (caster, spell->obj_flag))
	factor += 2;

      send_magic_msg (caster, caster, victim, spell->to_caster, TOCAST);
      send_magic_msg (victim, caster, victim, spell->to_victim, TOVIC);
      send_magic_msg (ploc (caster), caster, victim, spell->to_others, TOROOM);

      damage = spell->damage * factor;
    }
    /* Vampiric Touch */
    if (spell->verb == VERB_VTOUCH) {
      pscore (caster) = pscore (caster) + 100 * damage;
      sendf (caster, "&*You gain &+W%d &*experience points!\n", damage * 100);
      wound_player (caster, victim, damage, 0);
    }
    /* Light */
    if (spell->verb == VERB_LIT) {
      if (add_duration (victim, VERB_LIT, spell->duration * factor, 0))
	ssetflg (victim, SFL_LIT);
    }
    /* Damage */
    if (spell->verb == VERB_DAMAGE) {
      add_duration (victim, VERB_DAMAGE, spell->duration * factor, 0);
    }
    /* Armor */
    if (spell->verb == VERB_ARMOR) {
      add_duration (victim, VERB_ARMOR, spell->duration * factor, 0);
    }
    /* Blur */
    if (spell->verb == VERB_BLUR) {
      add_duration (victim, VERB_BLUR, spell->duration, 0);
    }
  }
  return True;
}

int
mob_cast_spell (int caster)
{
  struct SPELL *spell;

  for (spell = spell_table; spell->verb >= 0; spell++) {
    if (etstflg (caster, spell->flag) == 0)
      continue;
    if (randperc () < spell->chance)
      return spell->verb;
  }
  return -1;
}

Boolean
check_object (int plr, int flag)
{
  int i;

  if (flag == NOFLAG)
    return False;

  for (i = 0; i < pnumobs (plr); i++)
    if (iscarrby (pobj_nr (i, plr), flag) && otstbit (i, flag))
      return True;

  return False;
}

void
send_magic_msg (int dest, int caster, int victim, char *msg, int type)
{
  char xx[120];
  char c[30], v[30];

  if (msg == NULL)
    return;

  sprintf (c, "\001p%s\003", pname (caster));
  sprintf (v, "\001p%s\003", pname (victim));

  if (type == CASTER && caster == victim)
    sprintf (v, "yourself");
  if (type == ROOM && caster == victim)
    sprintf (v, "%sself", psex (caster) ? "her" : "him");
  if (type == VICTIM && caster == victim)
    return;
  if (type == TOCAST && caster == victim)
    return;

  if (type == ROOM || type == TOROOM)
    send_msg (dest, 0, LVL_MIN, LVL_MAX, caster, victim,
	      "%s\n", make_magic_msg (xx, msg, c, v));
  else
    send_msg (dest, 0, LVL_MIN, LVL_MAX, NOBODY, NOBODY,
	      "%s\n", make_magic_msg (xx, msg, c, v));
}

char *
make_magic_msg (char *b, char *s, char *c, char *v)
{
  char *p, *q, *r;

  for (p = b, q = s; *q != 0;) {
    if (*q != '%')
      *p++ = *q++;
    else {
      switch (*++q) {
      case 'c':		/* Caster */
	if (c == NULL)
	  return NULL;
	for (r = c; *r != 0;)
	  *p++ = *r++;
	break;
      case 'v':		/* Victim */
	if (v == NULL)
	  return NULL;
	for (r = v; *r != 0;)
	  *p++ = *r++;
	break;
      case 0:
	--q;
	break;
      default:
	*p++ = *q;
      }
      ++q;
    }
  }
  if (p[-1] == '\n')
    --p;
  *p = 0;
  return b;
}

/************************************************************************
 * Spell Duration Handler Functions					*
 ************************************************************************/

/* This function wipes out all of the duration data.
 */
void
wipe_duration (int plr)
{
  SPELL_DURATION *check = plr < max_players ? players[plr].duration : NULL;
  SPELL_DURATION *nextptr = NULL;

  while (check != NULL) {
    if (nextptr != NULL)
      check = nextptr;
    if (check->spell == VERB_LIT)
      sclrflg (plr, SFL_LIT);
    nextptr = check->next;
    FREE (check);
  }
}

/* This function sends text to a user that his/her spell has ended.
 */
void
duration_end (int plr, int spell, int tmp)
{
  if (spell == VERB_LIT) {
    sendf (plr, "Your lit spell expires.\n");
    sclrflg (plr, SFL_LIT);
  }
  if (spell == VERB_DAMAGE) {
    sendf (plr, "You feel your strength spell wearing off.\n");
    setpdam (plr, tmp);
  }
  if (spell == VERB_ARMOR) {
    sendf (plr, "You feel your protection spell wearing off.\n");
    setparmor (plr, tmp);
  }
  if (spell == VERB_BLUR) {
    sendf (plr, "You seem to be more visible.\n");
  }
}

/* This function adds a spell to a player's duration linklist.
 */
Boolean
add_duration (int plr, int spell, int duration, int tmp)
{
  /* Convert minutes to seconds. Since the MUD interrupts
   * once every 2 seconds though, we multiply by 30.
   */
  duration = duration * 30;

  /* Check to see if the spell is already being used */
  if (!check_duration (plr, spell)) {
    push_duration (plr, spell, duration, tmp);
    return True;
  } else {
    return False;
  }
}

/* This function checks if a spell is currently being used.
 */
Boolean
check_duration (int plr, int spell)
{
  SPELL_DURATION *check = plr < max_players ? players[plr].duration : NULL;

  if (check == NULL)
    return False;

  /* Check to see if the spell is already being used */
  while (check != NULL) {
    if (check->spell == spell)
      return True;
    check = check->next;
  }
  return False;
}

/* This function handles going through the linklist to decrement the
 * duration and check the spells.
 */
void
handle_duration (int plr)
{
  SPELL_DURATION *check = plr < max_players ? players[plr].duration : NULL;
  SPELL_DURATION *prev = NULL;

  /* Nothing is in the linklist, do not process. */
  if (check == NULL)
    return;

  /* Decrement all spells, disable if it ran out, and free memory */
  while (check != NULL) {
    if (!check->duration--) {
      duration_end (plr, check->spell, check->tmp);
      if (prev == NULL) {
	players[plr].duration = check->next;
	FREE (check);
      } else {
	prev->next = check->next;
	FREE (check);
	check = prev;
      }
    }
    prev = check;
    check = check->next;
  }
}

/* This function pushes the linklist to add another duration pointer
 * into it.
 */
void
push_duration (int plr, int spell, int duration, int tmp)
{
  SPELL_DURATION *new;
  SPELL_DURATION *curr = players[plr].duration;

  new = NEW (SPELL_DURATION, 1);
  new->spell = spell;
  new->duration = duration;
  new->tmp = tmp;

  if (curr != NULL) {
    new->next = curr->next;
    curr->next = new;
  } else {
    new->next = curr;
    curr = new;
  }
}