cdirt/ascii/
cdirt/data/BULL/
cdirt/data/ZONES/PENDING/
cdirt/pending/
cdirt/src/utils/
cdirt/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"

Boolean cast_spell(int, int, struct SPELL *);

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

  if ((pclass(mynum) != PRIEST && pclass(mynum) != MAGE) 
    && plev(mynum) < LVL_ISTARI && !etstflg(mynum, EFL_WHERE)) {
    bprintf("You have no spells.\n");
    return;
  }

  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) || plev(mynum) >= LVL_ISTARI) {
      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 verb) {
  struct SPELL *spell;
  int victim = brkword () < 0 ? pfighting (mynum) : fmbn (wordbuf);

  for (spell = spell_table; spell->verb != verb; spell++)
    if (spell->verb < 0)
      return;

  if (ststflg(mynum, SFL_DUMB) && plev(mynum) < LVL_WIZARD) {
    bprintf("Sorry, you been struck dumb.\n");
    return;
  }
  else if (!is_in_game(victim)) {
    bprintf ("Who?\n");
    return;
  }
  else if ((verb==VERB_BABEL || verb==VERB_MAKEPIG) && victim >= max_players) {
    bprintf("Those spells are for human players only.\n");
    return;
  }
  else if (plev(mynum) < LVL_ISTARI) {
    if (cur_player->cast_spell && pfighting(mynum))
      bprintf("You can't cast more than one spell per round.\n");
    else if (!etstflg(mynum, spell->flag))
      bprintf("You have not learned this spell yet.\n");
    else if (ploc(mynum) != ploc(victim))
      bprintf("%s is not here.\n", pname(victim));
    else if (pstr(victim) < 0)
      bprintf("%s is dead.\n", pname(victim));
    else if (pmagic(mynum) < spell->mana)
      bprintf("You are to weak to cast this spell.\n");
    else if (ltstflg (ploc (victim), LFL_NO_MAGIC))
      bprintf("Something about this area made you to fumble the magic.\n");
    else
      cast_spell (mynum, victim, spell); 
  }
  else
    cast_spell (mynum, victim, spell);
}

Boolean cast_spell (int caster, int victim, struct SPELL *spell) {
  int chance, damage;
  int factor = 1;

  Boolean miss = False;
  damage = 0;

  if (plev (caster) < LVL_WIZARD) {
    if (spell->type == ATTACK) {
      if (testpeace (caster)) {
        sendf (caster, "No, that's violent!\n");
        return False;
      }
      else if (victim < max_players && linkdead(victim)) {
        sendf(caster, "That player is linkdead.\n");
        return False;
      }
    }

   if (caster < max_players && victim < max_players && 
      !ltstflg(ploc(caster), LFL_PKZONE) && spell->type == ATTACK ) {
      bprintf("You cannot attack another player here!\n");
      send_msg(DEST_ALL, 0, LVL_WIZARD, LVL_MAX, NOBODY, NOBODY,
                "&#&+R[&+Y%s &+Rhas tried to kill &+Y%s&+R]\n",
                pname(caster), pname(victim));
      sendf(victim, "%s tried to attack you!\n", pname(caster));
      return False;
    }

    chance = spell->chance;

#ifdef LOCMIN_BLIZZARD
    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;
#endif

#ifdef LOCMIN_FANTASY
    if (carries_obj_type (caster, OBJ_FANTASY_MANA) > -1)
      chance += 2;
#endif

    if (caster < max_players) {
      players[caster].cast_spell = True;
      if (randperc () > (chance + 4 * plev(caster)))
        miss = True;
    }
    else 
     if (randperc() > (chance * CHANCE_MULTIPLIER))
       miss = True;

    if (ptstflg (victim, PFL_NOHASSLE)) {
      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( 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 && wears_antimagic(victim)) {
      if (randperc() < 50) { 
        sendf(caster, "The spell flashes harmlessly past %s!\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 flashes "
                  "harmlessly past %s!\n", pname (caster), pname (victim),
                  his_or_her (victim));
        sendf(victim, "%s casts a spell on you, but if flashes past "
                      "harmlessly!", see_name (victim, caster));
        return(False);
      }
      else {
        sendf(caster, "%s's antimagic item fails to protect %s!\n",
          pname(victim), psex(victim) ? "her" : "him");
        sendf(victim, "Your antimagic item fails to protect you.\n");
      }
    }
    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);

    /* calculate damage */

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

    /* vtouch : a special attack spell */

    if (spell->verb == VERB_VTOUCH) {
      if (etstflg(victim, EFL_N_VTOUCH)) {
	 sendf (caster, "%s drains your life instead!\n", pname(victim));
         pscore (caster) = pscore (caster) - 100 * damage;
         pscore (victim) = pscore (victim) + 100 * damage;
      }
      else {
        pscore (caster) = pscore (caster) + 100 * damage;
        pscore (victim) = pscore (victim) - 100 * damage;
        sendf (caster, "&*You gain &+W%d &*experience points!\n", damage * 100);
      }
      if (pfighting(victim) == -1)
        hit_player (victim, caster, pwpn(victim));
      return(True);
    }

    /* account for all ATTACK spells here, all require Neg entry */


    if (spell->verb == VERB_FIREBALL && etstflg(victim, EFL_N_FIREBALL))
       sendf (caster, "%s enjoys the &+Rheat&N and gets STRONGER!\n", pname(victim));
    else if (spell->verb == VERB_SHOCK && etstflg(victim, EFL_N_SHOCK))
       sendf (caster, "%s grows stronger from the charge!\n", pname(victim));
    else if (spell->verb == VERB_MISSILE && etstflg(victim, EFL_N_MISSILE))
       sendf (caster, "%s absorbs the &+Wmissile&N and grows STRONGER!\n", pname(victim));
    else if (spell->verb == VERB_FROST && etstflg(victim, EFL_N_FROST))
       sendf (caster, "%s likes the &+Ccold&N!\n", pname(victim));
    else if (spell->verb == VERB_ICESTORM && etstflg(victim, EFL_N_ICESTORM))
       sendf (caster, "%s relaxes and enjoys the cold weather.\n", pname(victim));
    else {
      switch (spell->verb) {
        case VERB_DEAFEN:
          add_duration(victim, VERB_DEAFEN, spell->duration, 0);
          ssetflg(victim, SFL_DEAF);
          break;
        case VERB_CRIPPLE:
          add_duration(victim, VERB_CRIPPLE, spell->duration, 0);
          ssetflg(victim, SFL_CRIPPLED);
          break;
        case VERB_MUTE:
          add_duration(victim, VERB_MUTE, spell->duration, 0);
          ssetflg(victim, SFL_DUMB);
          break;
        case VERB_BLIND:
          add_duration(victim, VERB_BLIND, spell->duration, 0);
          ssetflg(victim, SFL_BLIND);
          break;
        default:
          setpstr(victim, pstr(victim) - damage);         /* a normal spell: */
          if (pstr(victim) < 0)                           /* this place is */
            player_died(caster, victim, spell->verb);     /* where all damage */
        }
        if (pfighting(victim) == -1 && plev(caster) < LVL_WIZARD)
          hit_player (victim, caster, pwpn(victim));
        return(True);
    }

    setpstr(victim, pstr(victim) + damage);  /* fall thru -  spell negated */
    if (pfighting(victim) == -1)
      hit_player (victim, caster, pwpn(victim));
    return True;
  }

  /* Heal type spell */

  if (spell->type == HEAL) {
    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);
  }

  if (spell->type == SPECIAL) {
    if (victim >= max_players) {
      if (spell->verb != VERB_CRIPPLE && spell->verb != VERB_DEAFEN &&
         spell->verb != VERB_MUTE && spell->verb != VERB_BLIND)
        sendf (caster, "That doesn't make any sense.\n");
      return(False);
    }
    if (check_duration (victim, spell->verb)) {
      sendf(caster, "%s are already under the effects of that spell.\n",
	     caster == victim ? "You" : "They");
      return(False);
    }

    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;
    }

    /* spell has succeeded by this point */

    switch (spell->verb) {
      case VERB_LIT:
        if (add_duration(victim, VERB_LIT, spell->duration * factor, 0))
  	  ssetflg(victim, SFL_LIT);
        break;
      case VERB_DAMAGE:
        if (add_duration(victim, VERB_DAMAGE, spell->duration * factor, pdam(victim)))
  	  setpdam(victim, pdam (victim) + 10);
        break;
      case VERB_ARMOR:
        if (add_duration(victim, VERB_ARMOR, spell->duration * factor,
            parmor (victim))) {
  	  setparmor (victim, parmor (victim) + 10);
          calc_ac(victim);
        }
        break;
      case VERB_BLUR:
        add_duration (victim, VERB_BLUR, spell->duration, 0);
        break;
      case VERB_BABEL:
        add_duration(victim, VERB_BABEL, spell->duration, 0);
        ssetflg(victim, SFL_BABEL);
        send_msg(DEST_ALL, 0, LVL_ARCHWIZARD, LVL_MAX, mynum, victim,
	         "&+r[&+Y%s has cast babel spell on %s&+r]\n", pname(mynum),
	         pname(victim));
        break;
   
      case VERB_MAKEPIG:
        add_duration(victim, VERB_MAKEPIG, spell->duration, 0);
        ssetflg(victim, SFL_ISPIG);
        send_msg(DEST_ALL, 0, LVL_ARCHWIZARD, LVL_MAX, mynum, victim,
	         "&+r[&+y%s has cast makepig spell on %s&+r]\n", pname(mynum),
	         pname(victim));
        break;
    }
  }
  return(True);
}

/* improved & more-random */

void mob_cast_spell (int caster, int victim) {
  struct SPELL *spell;
  struct SPELL *choices[32];
  int len;

  if (ststflg(caster, SFL_DUMB))
    return; 

  for (spell = spell_table, len = 0 ; spell->verb >= 0 ; spell++) {
    if (etstflg(caster, spell->flag) && spell->type == ATTACK) {
      choices[len] = spell;
      len++;
    }
  }

  if (!len || plev(victim) >= LVL_WIZARD ||
     (randperc() > SPELL_CHANCE + len * SPELL_INCR))
    return;
  else
    cast_spell(caster, victim, choices[randperc() % len]);
}

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,
	      make_magic_msg (xx, msg, c, v));
  else
    send_msg (dest, 0, LVL_MIN, LVL_MAX, NOBODY, NOBODY,
	      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;
    }
  }
  *p = 0;
  return b;
}

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

/* This function wipes out all of the duration data. */

void wipe_duration (int plr) {
  SPELL_DURATION *ptr, *fptr;

  ptr = players[plr].duration;

  while (ptr) {
    duration_end(plr, ptr->spell, ptr->tmp);
    fptr = ptr;
    ptr = ptr->next;
    FREE (fptr);
  }
}

void duration_end (int plr, int spell, int tmp) {
  switch (spell) {
    case VERB_LIT:
      sendf (plr, "&+MYour &+Ylit &+Mspell expires.\n");
      sclrflg (plr, SFL_LIT);
      break;
    case VERB_DAMAGE:
      sendf (plr, "&+MYou feel your &+Ystrength &+Mspell wearing off.\n");
      setpdam (plr, tmp);
      break;
    case VERB_ARMOR:
      sendf (plr, "&+MYou feel your protective &+Yarmor &+Mspell wearing off.\n");
      setparmor (plr, tmp);
      calc_ac(plr);
      break;
    case VERB_BLUR:
      sendf (plr, "&+MYou seem to be more visible as the &+Yblur &+Mspell "
             "wears off.\n");
      break;
    case VERB_BABEL:
      sendf (plr, "You don't feel like talking as much anymore!\n");
      sclrflg(plr, SFL_BABEL);
      break;
    case VERB_MAKEPIG:
      sendf (plr, "You don't feel like a pig anymore!\n");
      sclrflg(plr, SFL_ISPIG);
      break;
    case VERB_DEAFEN:
      sendf (plr, "You can hear again!\n");
      sclrflg(plr, SFL_DEAF);
      break;
    case VERB_CRIPPLE:
      sendf (plr, "You can walk again!\n");
      sclrflg(plr, SFL_CRIPPLED);
      break;
    case VERB_BLIND:
      sendf (plr, "You can see again!\n");
      sclrflg(plr, SFL_BLIND);
      break;
    case VERB_MUTE:
      sendf (plr, "You can talk again!\n");
      sclrflg(plr, SFL_DUMB);
      break;
  }
}

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

  /* Ptr 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 *ptr;

  if (plr >= max_players)
    return False;

  ptr = players[plr].duration;

  /* Check to see if the spell is already being used */
  while (ptr != NULL) {
    if (ptr->spell == spell)
      return True;
    ptr = ptr->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 *ptr;
  SPELL_DURATION *prev;
  SPELL_DURATION *temp;

  /* Decrement all spells, disable if it ran out, and FREE memory */

  ptr = players[plr].duration;
  prev = NULL;

  while (ptr != NULL) {
    if (!ptr->duration--) {
      duration_end (plr, ptr->spell, ptr->tmp);
      if (!prev) {                          /* prev = NULL */
	temp = ptr;
	ptr = ptr->next;
	players[plr].duration = ptr;        /* new first node */     
        FREE (temp);
      } 
      else {                                /* prev unchanged */
	prev->next = ptr->next;
	temp = ptr;
	ptr = ptr->next;
	FREE (temp);
      }
    }
    else {                                  /* new prev */
      prev = ptr;
      ptr = ptr->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;

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

  new->next = players[plr].duration;
  players[plr].duration = new;
}