/ circle3.1 / src / spell_parser.c
spell_parser.c
   1  /* ************************************************************************
   2  *   File: spell_parser.c                                Part of CircleMUD *
   3  *  Usage: top-level magic routines; outside points of entry to magic sys. *
   4  *                                                                         *
   5  *  All rights reserved.  See license.doc for complete information.        *
   6  *                                                                         *
   7  *  Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University *
   8  *  CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.               *
   9  ************************************************************************ */
  10  
  11  
  12  #include "conf.h"
  13  #include "sysdep.h"
  14  
  15  
  16  #include "structs.h"
  17  #include "utils.h"
  18  #include "interpreter.h"
  19  #include "spells.h"
  20  #include "handler.h"
  21  #include "comm.h"
  22  #include "db.h"
  23  
  24  
  25  #define SINFO spell_info[spellnum]
  26  
  27  /* local globals */
  28  struct spell_info_type spell_info[TOP_SPELL_DEFINE + 1];
  29  
  30  /* local functions */
  31  void say_spell(struct char_data *ch, int spellnum, struct char_data *tch, struct obj_data *tobj);
  32  void spello(int spl, const char *name, int max_mana, int min_mana, int mana_change, int minpos, int targets, int violent, int routines, const char *wearoff);
  33  int mag_manacost(struct char_data *ch, int spellnum);
  34  ACMD(do_cast);
  35  void unused_spell(int spl);
  36  void mag_assign_spells(void);
  37  
  38  /*
  39   * This arrangement is pretty stupid, but the number of skills is limited by
  40   * the playerfile.  We can arbitrarily increase the number of skills by
  41   * increasing the space in the playerfile. Meanwhile, 200 should provide
  42   * ample slots for skills.
  43   */
  44  
  45  struct syllable {
  46    const char *org;
  47    const char *news;
  48  };
  49  
  50  
  51  struct syllable syls[] = {
  52    {" ", " "},
  53    {"ar", "abra"},
  54    {"ate", "i"},
  55    {"cau", "kada"},
  56    {"blind", "nose"},
  57    {"bur", "mosa"},
  58    {"cu", "judi"},
  59    {"de", "oculo"},
  60    {"dis", "mar"},
  61    {"ect", "kamina"},
  62    {"en", "uns"},
  63    {"gro", "cra"},
  64    {"light", "dies"},
  65    {"lo", "hi"},
  66    {"magi", "kari"},
  67    {"mon", "bar"},
  68    {"mor", "zak"},
  69    {"move", "sido"},
  70    {"ness", "lacri"},
  71    {"ning", "illa"},
  72    {"per", "duda"},
  73    {"ra", "gru"},
  74    {"re", "candus"},
  75    {"son", "sabru"},
  76    {"tect", "infra"},
  77    {"tri", "cula"},
  78    {"ven", "nofo"},
  79    {"word of", "inset"},
  80    {"a", "i"}, {"b", "v"}, {"c", "q"}, {"d", "m"}, {"e", "o"}, {"f", "y"}, {"g", "t"},
  81    {"h", "p"}, {"i", "u"}, {"j", "y"}, {"k", "t"}, {"l", "r"}, {"m", "w"}, {"n", "b"},
  82    {"o", "a"}, {"p", "s"}, {"q", "d"}, {"r", "f"}, {"s", "g"}, {"t", "h"}, {"u", "e"},
  83    {"v", "z"}, {"w", "x"}, {"x", "n"}, {"y", "l"}, {"z", "k"}, {"", ""}
  84  };
  85  
  86  const char *unused_spellname = "!UNUSED!"; /* So we can get &unused_spellname */
  87  
  88  int mag_manacost(struct char_data *ch, int spellnum)
  89  {
  90    return MAX(SINFO.mana_max - (SINFO.mana_change *
  91  		    (GET_LEVEL(ch) - SINFO.min_level[(int) GET_CLASS(ch)])),
  92  	     SINFO.mana_min);
  93  }
  94  
  95  
  96  void say_spell(struct char_data *ch, int spellnum, struct char_data *tch,
  97  	            struct obj_data *tobj)
  98  {
  99    char lbuf[256], buf[256], buf1[256], buf2[256];	/* FIXME */
 100    const char *format;
 101  
 102    struct char_data *i;
 103    int j, ofs = 0;
 104  
 105    *buf = '\0';
 106    strlcpy(lbuf, skill_name(spellnum), sizeof(lbuf));
 107  
 108    while (lbuf[ofs]) {
 109      for (j = 0; *(syls[j].org); j++) {
 110        if (!strncmp(syls[j].org, lbuf + ofs, strlen(syls[j].org))) {
 111  	strcat(buf, syls[j].news);	/* strcat: BAD */
 112  	ofs += strlen(syls[j].org);
 113          break;
 114        }
 115      }
 116      /* i.e., we didn't find a match in syls[] */
 117      if (!*syls[j].org) {
 118        log("No entry in syllable table for substring of '%s'", lbuf);
 119        ofs++;
 120      }
 121    }
 122  
 123    if (tch != NULL && IN_ROOM(tch) == IN_ROOM(ch)) {
 124      if (tch == ch)
 125        format = "$n closes $s eyes and utters the words, '%s'.";
 126      else
 127        format = "$n stares at $N and utters the words, '%s'.";
 128    } else if (tobj != NULL &&
 129  	     ((IN_ROOM(tobj) == IN_ROOM(ch)) || (tobj->carried_by == ch)))
 130      format = "$n stares at $p and utters the words, '%s'.";
 131    else
 132      format = "$n utters the words, '%s'.";
 133  
 134    snprintf(buf1, sizeof(buf1), format, skill_name(spellnum));
 135    snprintf(buf2, sizeof(buf2), format, buf);
 136  
 137    for (i = world[IN_ROOM(ch)].people; i; i = i->next_in_room) {
 138      if (i == ch || i == tch || !i->desc || !AWAKE(i))
 139        continue;
 140      if (GET_CLASS(ch) == GET_CLASS(i))
 141        perform_act(buf1, ch, tobj, tch, i);
 142      else
 143        perform_act(buf2, ch, tobj, tch, i);
 144    }
 145  
 146    if (tch != NULL && tch != ch && IN_ROOM(tch) == IN_ROOM(ch)) {
 147      snprintf(buf1, sizeof(buf1), "$n stares at you and utters the words, '%s'.",
 148  	    GET_CLASS(ch) == GET_CLASS(tch) ? skill_name(spellnum) : buf);
 149      act(buf1, FALSE, ch, NULL, tch, TO_VICT);
 150    }
 151  }
 152  
 153  /*
 154   * This function should be used anytime you are not 100% sure that you have
 155   * a valid spell/skill number.  A typical for() loop would not need to use
 156   * this because you can guarantee > 0 and <= TOP_SPELL_DEFINE.
 157   */
 158  const char *skill_name(int num)
 159  {
 160    if (num > 0 && num <= TOP_SPELL_DEFINE)
 161      return (spell_info[num].name);
 162    else if (num == -1)
 163      return ("UNUSED");
 164    else
 165      return ("UNDEFINED");
 166  }
 167  
 168  	 
 169  int find_skill_num(char *name)
 170  {
 171    int skindex, ok;
 172    char *temp, *temp2;
 173    char first[256], first2[256], tempbuf[256];
 174  
 175    for (skindex = 1; skindex <= TOP_SPELL_DEFINE; skindex++) {
 176      if (is_abbrev(name, spell_info[skindex].name))
 177        return (skindex);
 178  
 179      ok = TRUE;
 180      strlcpy(tempbuf, spell_info[skindex].name, sizeof(tempbuf));	/* strlcpy: OK */
 181      temp = any_one_arg(tempbuf, first);
 182      temp2 = any_one_arg(name, first2);
 183      while (*first && *first2 && ok) {
 184        if (!is_abbrev(first2, first))
 185  	ok = FALSE;
 186        temp = any_one_arg(temp, first);
 187        temp2 = any_one_arg(temp2, first2);
 188      }
 189  
 190      if (ok && !*first2)
 191        return (skindex);
 192    }
 193  
 194    return (-1);
 195  }
 196  
 197  
 198  
 199  /*
 200   * This function is the very heart of the entire magic system.  All
 201   * invocations of all types of magic -- objects, spoken and unspoken PC
 202   * and NPC spells, the works -- all come through this function eventually.
 203   * This is also the entry point for non-spoken or unrestricted spells.
 204   * Spellnum 0 is legal but silently ignored here, to make callers simpler.
 205   */
 206  int call_magic(struct char_data *caster, struct char_data *cvict,
 207  	     struct obj_data *ovict, int spellnum, int level, int casttype)
 208  {
 209    int savetype;
 210  
 211    if (spellnum < 1 || spellnum > TOP_SPELL_DEFINE)
 212      return (0);
 213  
 214    if (ROOM_FLAGGED(IN_ROOM(caster), ROOM_NOMAGIC)) {
 215      send_to_char(caster, "Your magic fizzles out and dies.\r\n");
 216      act("$n's magic fizzles out and dies.", FALSE, caster, 0, 0, TO_ROOM);
 217      return (0);
 218    }
 219    if (ROOM_FLAGGED(IN_ROOM(caster), ROOM_PEACEFUL) &&
 220        (SINFO.violent || IS_SET(SINFO.routines, MAG_DAMAGE))) {
 221      send_to_char(caster, "A flash of white light fills the room, dispelling your violent magic!\r\n");
 222      act("White light from no particular source suddenly fills the room, then vanishes.", FALSE, caster, 0, 0, TO_ROOM);
 223      return (0);
 224    }
 225    /* determine the type of saving throw */
 226    switch (casttype) {
 227    case CAST_STAFF:
 228    case CAST_SCROLL:
 229    case CAST_POTION:
 230    case CAST_WAND:
 231      savetype = SAVING_ROD;
 232      break;
 233    case CAST_SPELL:
 234      savetype = SAVING_SPELL;
 235      break;
 236    default:
 237      savetype = SAVING_BREATH;
 238      break;
 239    }
 240  
 241  
 242    if (IS_SET(SINFO.routines, MAG_DAMAGE))
 243      if (mag_damage(level, caster, cvict, spellnum, savetype) == -1)
 244        return (-1);	/* Successful and target died, don't cast again. */
 245  
 246    if (IS_SET(SINFO.routines, MAG_AFFECTS))
 247      mag_affects(level, caster, cvict, spellnum, savetype);
 248  
 249    if (IS_SET(SINFO.routines, MAG_UNAFFECTS))
 250      mag_unaffects(level, caster, cvict, spellnum, savetype);
 251  
 252    if (IS_SET(SINFO.routines, MAG_POINTS))
 253      mag_points(level, caster, cvict, spellnum, savetype);
 254  
 255    if (IS_SET(SINFO.routines, MAG_ALTER_OBJS))
 256      mag_alter_objs(level, caster, ovict, spellnum, savetype);
 257  
 258    if (IS_SET(SINFO.routines, MAG_GROUPS))
 259      mag_groups(level, caster, spellnum, savetype);
 260  
 261    if (IS_SET(SINFO.routines, MAG_MASSES))
 262      mag_masses(level, caster, spellnum, savetype);
 263  
 264    if (IS_SET(SINFO.routines, MAG_AREAS))
 265      mag_areas(level, caster, spellnum, savetype);
 266  
 267    if (IS_SET(SINFO.routines, MAG_SUMMONS))
 268      mag_summons(level, caster, ovict, spellnum, savetype);
 269  
 270    if (IS_SET(SINFO.routines, MAG_CREATIONS))
 271      mag_creations(level, caster, spellnum);
 272  
 273    if (IS_SET(SINFO.routines, MAG_MANUAL))
 274      switch (spellnum) {
 275      case SPELL_CHARM:		MANUAL_SPELL(spell_charm); break;
 276      case SPELL_CREATE_WATER:	MANUAL_SPELL(spell_create_water); break;
 277      case SPELL_DETECT_POISON:	MANUAL_SPELL(spell_detect_poison); break;
 278      case SPELL_ENCHANT_WEAPON:  MANUAL_SPELL(spell_enchant_weapon); break;
 279      case SPELL_IDENTIFY:	MANUAL_SPELL(spell_identify); break;
 280      case SPELL_LOCATE_OBJECT:   MANUAL_SPELL(spell_locate_object); break;
 281      case SPELL_SUMMON:		MANUAL_SPELL(spell_summon); break;
 282      case SPELL_WORD_OF_RECALL:  MANUAL_SPELL(spell_recall); break;
 283      case SPELL_TELEPORT:	MANUAL_SPELL(spell_teleport); break;
 284      }
 285  
 286    return (1);
 287  }
 288  
 289  /*
 290   * mag_objectmagic: This is the entry-point for all magic items.  This should
 291   * only be called by the 'quaff', 'use', 'recite', etc. routines.
 292   *
 293   * For reference, object values 0-3:
 294   * staff  - [0]	level	[1] max charges	[2] num charges	[3] spell num
 295   * wand   - [0]	level	[1] max charges	[2] num charges	[3] spell num
 296   * scroll - [0]	level	[1] spell num	[2] spell num	[3] spell num
 297   * potion - [0] level	[1] spell num	[2] spell num	[3] spell num
 298   *
 299   * Staves and wands will default to level 14 if the level is not specified;
 300   * the DikuMUD format did not specify staff and wand levels in the world
 301   * files (this is a CircleMUD enhancement).
 302   */
 303  void mag_objectmagic(struct char_data *ch, struct obj_data *obj,
 304  		          char *argument)
 305  {
 306    char arg[MAX_INPUT_LENGTH];
 307    int i, k;
 308    struct char_data *tch = NULL, *next_tch;
 309    struct obj_data *tobj = NULL;
 310  
 311    one_argument(argument, arg);
 312  
 313    k = generic_find(arg, FIND_CHAR_ROOM | FIND_OBJ_INV | FIND_OBJ_ROOM |
 314  		   FIND_OBJ_EQUIP, ch, &tch, &tobj);
 315  
 316    switch (GET_OBJ_TYPE(obj)) {
 317    case ITEM_STAFF:
 318      act("You tap $p three times on the ground.", FALSE, ch, obj, 0, TO_CHAR);
 319      if (obj->action_description)
 320        act(obj->action_description, FALSE, ch, obj, 0, TO_ROOM);
 321      else
 322        act("$n taps $p three times on the ground.", FALSE, ch, obj, 0, TO_ROOM);
 323  
 324      if (GET_OBJ_VAL(obj, 2) <= 0) {
 325        send_to_char(ch, "It seems powerless.\r\n");
 326        act("Nothing seems to happen.", FALSE, ch, obj, 0, TO_ROOM);
 327      } else {
 328        GET_OBJ_VAL(obj, 2)--;
 329        WAIT_STATE(ch, PULSE_VIOLENCE);
 330        /* Level to cast spell at. */
 331        k = GET_OBJ_VAL(obj, 0) ? GET_OBJ_VAL(obj, 0) : DEFAULT_STAFF_LVL;
 332  
 333        /*
 334         * Problem : Area/mass spells on staves can cause crashes.
 335         * Solution: Remove the special nature of area/mass spells on staves.
 336         * Problem : People like that behavior.
 337         * Solution: We special case the area/mass spells here.
 338         */
 339        if (HAS_SPELL_ROUTINE(GET_OBJ_VAL(obj, 3), MAG_MASSES | MAG_AREAS)) {
 340          for (i = 0, tch = world[IN_ROOM(ch)].people; tch; tch = tch->next_in_room)
 341  	  i++;
 342  	while (i-- > 0)
 343  	  call_magic(ch, NULL, NULL, GET_OBJ_VAL(obj, 3), k, CAST_STAFF);
 344        } else {
 345  	for (tch = world[IN_ROOM(ch)].people; tch; tch = next_tch) {
 346  	  next_tch = tch->next_in_room;
 347  	  if (ch != tch)
 348  	    call_magic(ch, tch, NULL, GET_OBJ_VAL(obj, 3), k, CAST_STAFF);
 349  	}
 350        }
 351      }
 352      break;
 353    case ITEM_WAND:
 354      if (k == FIND_CHAR_ROOM) {
 355        if (tch == ch) {
 356  	act("You point $p at yourself.", FALSE, ch, obj, 0, TO_CHAR);
 357  	act("$n points $p at $mself.", FALSE, ch, obj, 0, TO_ROOM);
 358        } else {
 359  	act("You point $p at $N.", FALSE, ch, obj, tch, TO_CHAR);
 360  	if (obj->action_description)
 361  	  act(obj->action_description, FALSE, ch, obj, tch, TO_ROOM);
 362  	else
 363  	  act("$n points $p at $N.", TRUE, ch, obj, tch, TO_ROOM);
 364        }
 365      } else if (tobj != NULL) {
 366        act("You point $p at $P.", FALSE, ch, obj, tobj, TO_CHAR);
 367        if (obj->action_description)
 368  	act(obj->action_description, FALSE, ch, obj, tobj, TO_ROOM);
 369        else
 370  	act("$n points $p at $P.", TRUE, ch, obj, tobj, TO_ROOM);
 371      } else if (IS_SET(spell_info[GET_OBJ_VAL(obj, 3)].routines, MAG_AREAS | MAG_MASSES)) {
 372        /* Wands with area spells don't need to be pointed. */
 373        act("You point $p outward.", FALSE, ch, obj, NULL, TO_CHAR);
 374        act("$n points $p outward.", TRUE, ch, obj, NULL, TO_ROOM);
 375      } else {
 376        act("At what should $p be pointed?", FALSE, ch, obj, NULL, TO_CHAR);
 377        return;
 378      }
 379  
 380      if (GET_OBJ_VAL(obj, 2) <= 0) {
 381        send_to_char(ch, "It seems powerless.\r\n");
 382        act("Nothing seems to happen.", FALSE, ch, obj, 0, TO_ROOM);
 383        return;
 384      }
 385      GET_OBJ_VAL(obj, 2)--;
 386      WAIT_STATE(ch, PULSE_VIOLENCE);
 387      if (GET_OBJ_VAL(obj, 0))
 388        call_magic(ch, tch, tobj, GET_OBJ_VAL(obj, 3),
 389  		 GET_OBJ_VAL(obj, 0), CAST_WAND);
 390      else
 391        call_magic(ch, tch, tobj, GET_OBJ_VAL(obj, 3),
 392  		 DEFAULT_WAND_LVL, CAST_WAND);
 393      break;
 394    case ITEM_SCROLL:
 395      if (*arg) {
 396        if (!k) {
 397  	act("There is nothing to here to affect with $p.", FALSE,
 398  	    ch, obj, NULL, TO_CHAR);
 399  	return;
 400        }
 401      } else
 402        tch = ch;
 403  
 404      act("You recite $p which dissolves.", TRUE, ch, obj, 0, TO_CHAR);
 405      if (obj->action_description)
 406        act(obj->action_description, FALSE, ch, obj, NULL, TO_ROOM);
 407      else
 408        act("$n recites $p.", FALSE, ch, obj, NULL, TO_ROOM);
 409  
 410      WAIT_STATE(ch, PULSE_VIOLENCE);
 411      for (i = 1; i <= 3; i++)
 412        if (call_magic(ch, tch, tobj, GET_OBJ_VAL(obj, i),
 413  		       GET_OBJ_VAL(obj, 0), CAST_SCROLL) <= 0)
 414  	break;
 415  
 416      if (obj != NULL)
 417        extract_obj(obj);
 418      break;
 419    case ITEM_POTION:
 420      tch = ch;
 421      act("You quaff $p.", FALSE, ch, obj, NULL, TO_CHAR);
 422      if (obj->action_description)
 423        act(obj->action_description, FALSE, ch, obj, NULL, TO_ROOM);
 424      else
 425        act("$n quaffs $p.", TRUE, ch, obj, NULL, TO_ROOM);
 426  
 427      WAIT_STATE(ch, PULSE_VIOLENCE);
 428      for (i = 1; i <= 3; i++)
 429        if (call_magic(ch, ch, NULL, GET_OBJ_VAL(obj, i),
 430  		       GET_OBJ_VAL(obj, 0), CAST_POTION) <= 0)
 431  	break;
 432  
 433      if (obj != NULL)
 434        extract_obj(obj);
 435      break;
 436    default:
 437      log("SYSERR: Unknown object_type %d in mag_objectmagic.",
 438  	GET_OBJ_TYPE(obj));
 439      break;
 440    }
 441  }
 442  
 443  
 444  /*
 445   * cast_spell is used generically to cast any spoken spell, assuming we
 446   * already have the target char/obj and spell number.  It checks all
 447   * restrictions, etc., prints the words, etc.
 448   *
 449   * Entry point for NPC casts.  Recommended entry point for spells cast
 450   * by NPCs via specprocs.
 451   */
 452  int cast_spell(struct char_data *ch, struct char_data *tch,
 453  	           struct obj_data *tobj, int spellnum)
 454  {
 455    if (spellnum < 0 || spellnum > TOP_SPELL_DEFINE) {
 456      log("SYSERR: cast_spell trying to call spellnum %d/%d.", spellnum,
 457  	TOP_SPELL_DEFINE);
 458      return (0);
 459    }
 460      
 461    if (GET_POS(ch) < SINFO.min_position) {
 462      switch (GET_POS(ch)) {
 463        case POS_SLEEPING:
 464        send_to_char(ch, "You dream about great magical powers.\r\n");
 465        break;
 466      case POS_RESTING:
 467        send_to_char(ch, "You cannot concentrate while resting.\r\n");
 468        break;
 469      case POS_SITTING:
 470        send_to_char(ch, "You can't do this sitting!\r\n");
 471        break;
 472      case POS_FIGHTING:
 473        send_to_char(ch, "Impossible!  You can't concentrate enough!\r\n");
 474        break;
 475      default:
 476        send_to_char(ch, "You can't do much of anything like this!\r\n");
 477        break;
 478      }
 479      return (0);
 480    }
 481    if (AFF_FLAGGED(ch, AFF_CHARM) && (ch->master == tch)) {
 482      send_to_char(ch, "You are afraid you might hurt your master!\r\n");
 483      return (0);
 484    }
 485    if ((tch != ch) && IS_SET(SINFO.targets, TAR_SELF_ONLY)) {
 486      send_to_char(ch, "You can only cast this spell upon yourself!\r\n");
 487      return (0);
 488    }
 489    if ((tch == ch) && IS_SET(SINFO.targets, TAR_NOT_SELF)) {
 490      send_to_char(ch, "You cannot cast this spell upon yourself!\r\n");
 491      return (0);
 492    }
 493    if (IS_SET(SINFO.routines, MAG_GROUPS) && !AFF_FLAGGED(ch, AFF_GROUP)) {
 494      send_to_char(ch, "You can't cast this spell if you're not in a group!\r\n");
 495      return (0);
 496    }
 497    send_to_char(ch, "%s", OK);
 498    say_spell(ch, spellnum, tch, tobj);
 499  
 500    return (call_magic(ch, tch, tobj, spellnum, GET_LEVEL(ch), CAST_SPELL));
 501  }
 502  
 503  
 504  /*
 505   * do_cast is the entry point for PC-casted spells.  It parses the arguments,
 506   * determines the spell number and finds a target, throws the die to see if
 507   * the spell can be cast, checks for sufficient mana and subtracts it, and
 508   * passes control to cast_spell().
 509   */
 510  ACMD(do_cast)
 511  {
 512    struct char_data *tch = NULL;
 513    struct obj_data *tobj = NULL;
 514    char *s, *t;
 515    int mana, spellnum, i, target = 0;
 516  
 517    if (IS_NPC(ch))
 518      return;
 519  
 520    /* get: blank, spell name, target name */
 521    s = strtok(argument, "'");
 522  
 523    if (s == NULL) {
 524      send_to_char(ch, "Cast what where?\r\n");
 525      return;
 526    }
 527    s = strtok(NULL, "'");
 528    if (s == NULL) {
 529      send_to_char(ch, "Spell names must be enclosed in the Holy Magic Symbols: '\r\n");
 530      return;
 531    }
 532    t = strtok(NULL, "\0");
 533  
 534    /* spellnum = search_block(s, spells, 0); */
 535    spellnum = find_skill_num(s);
 536  
 537    if ((spellnum < 1) || (spellnum > MAX_SPELLS)) {
 538      send_to_char(ch, "Cast what?!?\r\n");
 539      return;
 540    }
 541    if (GET_LEVEL(ch) < SINFO.min_level[(int) GET_CLASS(ch)]) {
 542      send_to_char(ch, "You do not know that spell!\r\n");
 543      return;
 544    }
 545    if (GET_SKILL(ch, spellnum) == 0) {
 546      send_to_char(ch, "You are unfamiliar with that spell.\r\n");
 547      return;
 548    }
 549    /* Find the target */
 550    if (t != NULL) {
 551      char arg[MAX_INPUT_LENGTH];
 552  
 553      strlcpy(arg, t, sizeof(arg));
 554      one_argument(arg, t);
 555      skip_spaces(&t);
 556    }
 557    if (IS_SET(SINFO.targets, TAR_IGNORE)) {
 558      target = TRUE;
 559    } else if (t != NULL && *t) {
 560      if (!target && (IS_SET(SINFO.targets, TAR_CHAR_ROOM))) {
 561        if ((tch = get_char_vis(ch, t, NULL, FIND_CHAR_ROOM)) != NULL)
 562  	target = TRUE;
 563      }
 564      if (!target && IS_SET(SINFO.targets, TAR_CHAR_WORLD))
 565        if ((tch = get_char_vis(ch, t, NULL, FIND_CHAR_WORLD)) != NULL)
 566  	target = TRUE;
 567  
 568      if (!target && IS_SET(SINFO.targets, TAR_OBJ_INV))
 569        if ((tobj = get_obj_in_list_vis(ch, t, NULL, ch->carrying)) != NULL)
 570  	target = TRUE;
 571  
 572      if (!target && IS_SET(SINFO.targets, TAR_OBJ_EQUIP)) {
 573        for (i = 0; !target && i < NUM_WEARS; i++)
 574  	if (GET_EQ(ch, i) && isname(t, GET_EQ(ch, i)->name)) {
 575  	  tobj = GET_EQ(ch, i);
 576  	  target = TRUE;
 577  	}
 578      }
 579      if (!target && IS_SET(SINFO.targets, TAR_OBJ_ROOM))
 580        if ((tobj = get_obj_in_list_vis(ch, t, NULL, world[IN_ROOM(ch)].contents)) != NULL)
 581  	target = TRUE;
 582  
 583      if (!target && IS_SET(SINFO.targets, TAR_OBJ_WORLD))
 584        if ((tobj = get_obj_vis(ch, t, NULL)) != NULL)
 585  	target = TRUE;
 586  
 587    } else {			/* if target string is empty */
 588      if (!target && IS_SET(SINFO.targets, TAR_FIGHT_SELF))
 589        if (FIGHTING(ch) != NULL) {
 590  	tch = ch;
 591  	target = TRUE;
 592        }
 593      if (!target && IS_SET(SINFO.targets, TAR_FIGHT_VICT))
 594        if (FIGHTING(ch) != NULL) {
 595  	tch = FIGHTING(ch);
 596  	target = TRUE;
 597        }
 598      /* if no target specified, and the spell isn't violent, default to self */
 599      if (!target && IS_SET(SINFO.targets, TAR_CHAR_ROOM) &&
 600  	!SINFO.violent) {
 601        tch = ch;
 602        target = TRUE;
 603      }
 604      if (!target) {
 605        send_to_char(ch, "Upon %s should the spell be cast?\r\n",
 606  		IS_SET(SINFO.targets, TAR_OBJ_ROOM | TAR_OBJ_INV | TAR_OBJ_WORLD | TAR_OBJ_EQUIP) ? "what" : "who");
 607        return;
 608      }
 609    }
 610  
 611    if (target && (tch == ch) && SINFO.violent) {
 612      send_to_char(ch, "You shouldn't cast that on yourself -- could be bad for your health!\r\n");
 613      return;
 614    }
 615    if (!target) {
 616      send_to_char(ch, "Cannot find the target of your spell!\r\n");
 617      return;
 618    }
 619    mana = mag_manacost(ch, spellnum);
 620    if ((mana > 0) && (GET_MANA(ch) < mana) && (GET_LEVEL(ch) < LVL_IMMORT)) {
 621      send_to_char(ch, "You haven't the energy to cast that spell!\r\n");
 622      return;
 623    }
 624  
 625    /* You throws the dice and you takes your chances.. 101% is total failure */
 626    if (rand_number(0, 101) > GET_SKILL(ch, spellnum)) {
 627      WAIT_STATE(ch, PULSE_VIOLENCE);
 628      if (!tch || !skill_message(0, ch, tch, spellnum))
 629        send_to_char(ch, "You lost your concentration!\r\n");
 630      if (mana > 0)
 631        GET_MANA(ch) = MAX(0, MIN(GET_MAX_MANA(ch), GET_MANA(ch) - (mana / 2)));
 632      if (SINFO.violent && tch && IS_NPC(tch))
 633        hit(tch, ch, TYPE_UNDEFINED);
 634    } else { /* cast spell returns 1 on success; subtract mana & set waitstate */
 635      if (cast_spell(ch, tch, tobj, spellnum)) {
 636        WAIT_STATE(ch, PULSE_VIOLENCE);
 637        if (mana > 0)
 638  	GET_MANA(ch) = MAX(0, MIN(GET_MAX_MANA(ch), GET_MANA(ch) - mana));
 639      }
 640    }
 641  }
 642  
 643  
 644  
 645  void spell_level(int spell, int chclass, int level)
 646  {
 647    int bad = 0;
 648  
 649    if (spell < 0 || spell > TOP_SPELL_DEFINE) {
 650      log("SYSERR: attempting assign to illegal spellnum %d/%d", spell, TOP_SPELL_DEFINE);
 651      return;
 652    }
 653  
 654    if (chclass < 0 || chclass >= NUM_CLASSES) {
 655      log("SYSERR: assigning '%s' to illegal class %d/%d.", skill_name(spell),
 656  		chclass, NUM_CLASSES - 1);
 657      bad = 1;
 658    }
 659  
 660    if (level < 1 || level > LVL_IMPL) {
 661      log("SYSERR: assigning '%s' to illegal level %d/%d.", skill_name(spell),
 662  		level, LVL_IMPL);
 663      bad = 1;
 664    }
 665  
 666    if (!bad)    
 667      spell_info[spell].min_level[chclass] = level;
 668  }
 669  
 670  
 671  /* Assign the spells on boot up */
 672  void spello(int spl, const char *name, int max_mana, int min_mana,
 673  	int mana_change, int minpos, int targets, int violent, int routines, const char *wearoff)
 674  {
 675    int i;
 676  
 677    for (i = 0; i < NUM_CLASSES; i++)
 678      spell_info[spl].min_level[i] = LVL_IMMORT;
 679    spell_info[spl].mana_max = max_mana;
 680    spell_info[spl].mana_min = min_mana;
 681    spell_info[spl].mana_change = mana_change;
 682    spell_info[spl].min_position = minpos;
 683    spell_info[spl].targets = targets;
 684    spell_info[spl].violent = violent;
 685    spell_info[spl].routines = routines;
 686    spell_info[spl].name = name;
 687    spell_info[spl].wear_off_msg = wearoff;
 688  }
 689  
 690  
 691  void unused_spell(int spl)
 692  {
 693    int i;
 694  
 695    for (i = 0; i < NUM_CLASSES; i++)
 696      spell_info[spl].min_level[i] = LVL_IMPL + 1;
 697    spell_info[spl].mana_max = 0;
 698    spell_info[spl].mana_min = 0;
 699    spell_info[spl].mana_change = 0;
 700    spell_info[spl].min_position = 0;
 701    spell_info[spl].targets = 0;
 702    spell_info[spl].violent = 0;
 703    spell_info[spl].routines = 0;
 704    spell_info[spl].name = unused_spellname;
 705  }
 706  
 707  #define skillo(skill, name) spello(skill, name, 0, 0, 0, 0, 0, 0, 0, NULL);
 708  
 709  
 710  /*
 711   * Arguments for spello calls:
 712   *
 713   * spellnum, maxmana, minmana, manachng, minpos, targets, violent?, routines.
 714   *
 715   * spellnum:  Number of the spell.  Usually the symbolic name as defined in
 716   * spells.h (such as SPELL_HEAL).
 717   *
 718   * spellname: The name of the spell.
 719   *
 720   * maxmana :  The maximum mana this spell will take (i.e., the mana it
 721   * will take when the player first gets the spell).
 722   *
 723   * minmana :  The minimum mana this spell will take, no matter how high
 724   * level the caster is.
 725   *
 726   * manachng:  The change in mana for the spell from level to level.  This
 727   * number should be positive, but represents the reduction in mana cost as
 728   * the caster's level increases.
 729   *
 730   * minpos  :  Minimum position the caster must be in for the spell to work
 731   * (usually fighting or standing). targets :  A "list" of the valid targets
 732   * for the spell, joined with bitwise OR ('|').
 733   *
 734   * violent :  TRUE or FALSE, depending on if this is considered a violent
 735   * spell and should not be cast in PEACEFUL rooms or on yourself.  Should be
 736   * set on any spell that inflicts damage, is considered aggressive (i.e.
 737   * charm, curse), or is otherwise nasty.
 738   *
 739   * routines:  A list of magic routines which are associated with this spell
 740   * if the spell uses spell templates.  Also joined with bitwise OR ('|').
 741   *
 742   * See the CircleMUD documentation for a more detailed description of these
 743   * fields.
 744   */
 745  
 746  /*
 747   * NOTE: SPELL LEVELS ARE NO LONGER ASSIGNED HERE AS OF Circle 3.0 bpl9.
 748   * In order to make this cleaner, as well as to make adding new classes
 749   * much easier, spell levels are now assigned in class.c.  You only need
 750   * a spello() call to define a new spell; to decide who gets to use a spell
 751   * or skill, look in class.c.  -JE 5 Feb 1996
 752   */
 753  
 754  void mag_assign_spells(void)
 755  {
 756    int i;
 757  
 758    /* Do not change the loop below. */
 759    for (i = 0; i <= TOP_SPELL_DEFINE; i++)
 760      unused_spell(i);
 761    /* Do not change the loop above. */
 762  
 763    spello(SPELL_ANIMATE_DEAD, "animate dead", 35, 10, 3, POS_STANDING,
 764  	TAR_OBJ_ROOM, FALSE, MAG_SUMMONS,
 765  	NULL);
 766  
 767    spello(SPELL_ARMOR, "armor", 30, 15, 3, POS_FIGHTING,
 768  	TAR_CHAR_ROOM, FALSE, MAG_AFFECTS,
 769  	"You feel less protected.");
 770  
 771    spello(SPELL_BLESS, "bless", 35, 5, 3, POS_STANDING,
 772  	TAR_CHAR_ROOM | TAR_OBJ_INV, FALSE, MAG_AFFECTS | MAG_ALTER_OBJS,
 773  	"You feel less righteous.");
 774  
 775    spello(SPELL_BLINDNESS, "blindness", 35, 25, 1, POS_STANDING,
 776  	TAR_CHAR_ROOM | TAR_NOT_SELF, FALSE, MAG_AFFECTS,
 777  	"You feel a cloak of blindness dissolve.");
 778  
 779    spello(SPELL_BURNING_HANDS, "burning hands", 30, 10, 3, POS_FIGHTING,
 780  	TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE,
 781  	NULL);
 782  
 783    spello(SPELL_CALL_LIGHTNING, "call lightning", 40, 25, 3, POS_FIGHTING,
 784  	TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE,
 785  	NULL);
 786  
 787    spello(SPELL_CHARM, "charm person", 75, 50, 2, POS_FIGHTING,
 788  	TAR_CHAR_ROOM | TAR_NOT_SELF, TRUE, MAG_MANUAL,
 789  	"You feel more self-confident.");
 790  
 791    spello(SPELL_CHILL_TOUCH, "chill touch", 30, 10, 3, POS_FIGHTING,
 792  	TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE | MAG_AFFECTS,
 793  	"You feel your strength return.");
 794  
 795    spello(SPELL_CLONE, "clone", 80, 65, 5, POS_STANDING,
 796  	TAR_SELF_ONLY, FALSE, MAG_SUMMONS,
 797  	NULL);
 798  
 799    spello(SPELL_COLOR_SPRAY, "color spray", 30, 15, 3, POS_FIGHTING,
 800  	TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE,
 801  	NULL);
 802  
 803    spello(SPELL_CONTROL_WEATHER, "control weather", 75, 25, 5, POS_STANDING,
 804  	TAR_IGNORE, FALSE, MAG_MANUAL,
 805  	NULL);
 806  
 807    spello(SPELL_CREATE_FOOD, "create food", 30, 5, 4, POS_STANDING,
 808  	TAR_IGNORE, FALSE, MAG_CREATIONS,
 809  	NULL);
 810  
 811    spello(SPELL_CREATE_WATER, "create water", 30, 5, 4, POS_STANDING,
 812  	TAR_OBJ_INV | TAR_OBJ_EQUIP, FALSE, MAG_MANUAL,
 813  	NULL);
 814  
 815    spello(SPELL_CURE_BLIND, "cure blind", 30, 5, 2, POS_STANDING,
 816  	TAR_CHAR_ROOM, FALSE, MAG_UNAFFECTS,
 817  	NULL);
 818  
 819    spello(SPELL_CURE_CRITIC, "cure critic", 30, 10, 2, POS_FIGHTING,
 820  	TAR_CHAR_ROOM, FALSE, MAG_POINTS,
 821  	NULL);
 822  
 823    spello(SPELL_CURE_LIGHT, "cure light", 30, 10, 2, POS_FIGHTING,
 824  	TAR_CHAR_ROOM, FALSE, MAG_POINTS,
 825  	NULL);
 826  
 827    spello(SPELL_CURSE, "curse", 80, 50, 2, POS_STANDING,
 828  	TAR_CHAR_ROOM | TAR_OBJ_INV, TRUE, MAG_AFFECTS | MAG_ALTER_OBJS,
 829  	"You feel more optimistic.");
 830  
 831    spello(SPELL_DETECT_ALIGN, "detect alignment", 20, 10, 2, POS_STANDING,
 832  	TAR_CHAR_ROOM | TAR_SELF_ONLY, FALSE, MAG_AFFECTS,
 833  	"You feel less aware.");
 834  
 835    spello(SPELL_DETECT_INVIS, "detect invisibility", 20, 10, 2, POS_STANDING,
 836  	TAR_CHAR_ROOM | TAR_SELF_ONLY, FALSE, MAG_AFFECTS,
 837  	"Your eyes stop tingling.");
 838  
 839    spello(SPELL_DETECT_MAGIC, "detect magic", 20, 10, 2, POS_STANDING,
 840  	TAR_CHAR_ROOM | TAR_SELF_ONLY, FALSE, MAG_AFFECTS,
 841  	"The detect magic wears off.");
 842  
 843    spello(SPELL_DETECT_POISON, "detect poison", 15, 5, 1, POS_STANDING,
 844  	TAR_CHAR_ROOM | TAR_OBJ_INV | TAR_OBJ_ROOM, FALSE, MAG_MANUAL,
 845  	"The detect poison wears off.");
 846  
 847    spello(SPELL_DISPEL_EVIL, "dispel evil", 40, 25, 3, POS_FIGHTING,
 848  	TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE,
 849  	NULL);
 850  
 851    spello(SPELL_DISPEL_GOOD, "dispel good", 40, 25, 3, POS_FIGHTING,
 852  	TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE,
 853  	NULL);
 854  
 855    spello(SPELL_EARTHQUAKE, "earthquake", 40, 25, 3, POS_FIGHTING,
 856  	TAR_IGNORE, TRUE, MAG_AREAS,
 857  	NULL);
 858  
 859    spello(SPELL_ENCHANT_WEAPON, "enchant weapon", 150, 100, 10, POS_STANDING,
 860  	TAR_OBJ_INV, FALSE, MAG_MANUAL,
 861  	NULL);
 862  
 863    spello(SPELL_ENERGY_DRAIN, "energy drain", 40, 25, 1, POS_FIGHTING,
 864  	TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE | MAG_MANUAL,
 865  	NULL);
 866  
 867    spello(SPELL_GROUP_ARMOR, "group armor", 50, 30, 2, POS_STANDING,
 868  	TAR_IGNORE, FALSE, MAG_GROUPS,
 869  	NULL);
 870  
 871    spello(SPELL_FIREBALL, "fireball", 40, 30, 2, POS_FIGHTING,
 872  	TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE,
 873  	NULL);
 874  
 875    spello(SPELL_GROUP_HEAL, "group heal", 80, 60, 5, POS_STANDING,
 876  	TAR_IGNORE, FALSE, MAG_GROUPS,
 877  	NULL);
 878  
 879    spello(SPELL_HARM, "harm", 75, 45, 3, POS_FIGHTING,
 880  	TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE,
 881  	NULL);
 882  
 883    spello(SPELL_HEAL, "heal", 60, 40, 3, POS_FIGHTING,
 884  	TAR_CHAR_ROOM, FALSE, MAG_POINTS | MAG_UNAFFECTS,
 885  	NULL);
 886  
 887    spello(SPELL_INFRAVISION, "infravision", 25, 10, 1, POS_STANDING,
 888  	TAR_CHAR_ROOM | TAR_SELF_ONLY, FALSE, MAG_AFFECTS,
 889  	"Your night vision seems to fade.");
 890  
 891    spello(SPELL_INVISIBLE, "invisibility", 35, 25, 1, POS_STANDING,
 892  	TAR_CHAR_ROOM | TAR_OBJ_INV | TAR_OBJ_ROOM, FALSE, MAG_AFFECTS | MAG_ALTER_OBJS,
 893  	"You feel yourself exposed.");
 894  
 895    spello(SPELL_LIGHTNING_BOLT, "lightning bolt", 30, 15, 1, POS_FIGHTING,
 896  	TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE,
 897  	NULL);
 898  
 899    spello(SPELL_LOCATE_OBJECT, "locate object", 25, 20, 1, POS_STANDING,
 900  	TAR_OBJ_WORLD, FALSE, MAG_MANUAL,
 901  	NULL);
 902  
 903    spello(SPELL_MAGIC_MISSILE, "magic missile", 25, 10, 3, POS_FIGHTING,
 904  	TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE,
 905  	NULL);
 906  
 907    spello(SPELL_POISON, "poison", 50, 20, 3, POS_STANDING,
 908  	TAR_CHAR_ROOM | TAR_NOT_SELF | TAR_OBJ_INV, TRUE,
 909  	MAG_AFFECTS | MAG_ALTER_OBJS,
 910  	"You feel less sick.");
 911  
 912    spello(SPELL_PROT_FROM_EVIL, "protection from evil", 40, 10, 3, POS_STANDING,
 913  	TAR_CHAR_ROOM | TAR_SELF_ONLY, FALSE, MAG_AFFECTS,
 914  	"You feel less protected.");
 915  
 916    spello(SPELL_REMOVE_CURSE, "remove curse", 45, 25, 5, POS_STANDING,
 917  	TAR_CHAR_ROOM | TAR_OBJ_INV | TAR_OBJ_EQUIP, FALSE,
 918  	MAG_UNAFFECTS | MAG_ALTER_OBJS,
 919  	NULL);
 920  
 921    spello(SPELL_REMOVE_POISON, "remove poison", 40, 8, 4, POS_STANDING,
 922  	TAR_CHAR_ROOM | TAR_OBJ_INV | TAR_OBJ_ROOM, FALSE, MAG_UNAFFECTS | MAG_ALTER_OBJS,
 923  	NULL);
 924  
 925    spello(SPELL_SANCTUARY, "sanctuary", 110, 85, 5, POS_STANDING,
 926  	TAR_CHAR_ROOM, FALSE, MAG_AFFECTS,
 927  	"The white aura around your body fades.");
 928  
 929    spello(SPELL_SENSE_LIFE, "sense life", 20, 10, 2, POS_STANDING,
 930  	TAR_CHAR_ROOM | TAR_SELF_ONLY, FALSE, MAG_AFFECTS,
 931  	"You feel less aware of your surroundings.");
 932  
 933    spello(SPELL_SHOCKING_GRASP, "shocking grasp", 30, 15, 3, POS_FIGHTING,
 934  	TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE,
 935  	NULL);
 936  
 937    spello(SPELL_SLEEP, "sleep", 40, 25, 5, POS_STANDING,
 938  	TAR_CHAR_ROOM, TRUE, MAG_AFFECTS,
 939  	"You feel less tired.");
 940  
 941    spello(SPELL_STRENGTH, "strength", 35, 30, 1, POS_STANDING,
 942  	TAR_CHAR_ROOM, FALSE, MAG_AFFECTS,
 943  	"You feel weaker.");
 944  
 945    spello(SPELL_SUMMON, "summon", 75, 50, 3, POS_STANDING,
 946  	TAR_CHAR_WORLD | TAR_NOT_SELF, FALSE, MAG_MANUAL,
 947  	NULL);
 948  
 949    spello(SPELL_TELEPORT, "teleport", 75, 50, 3, POS_STANDING,
 950  	TAR_CHAR_ROOM, FALSE, MAG_MANUAL,
 951  	NULL);
 952  
 953    spello(SPELL_WATERWALK, "waterwalk", 40, 20, 2, POS_STANDING,
 954  	TAR_CHAR_ROOM, FALSE, MAG_AFFECTS,
 955  	"Your feet seem less buoyant.");
 956  
 957    spello(SPELL_WORD_OF_RECALL, "word of recall", 20, 10, 2, POS_FIGHTING,
 958  	TAR_CHAR_ROOM, FALSE, MAG_MANUAL,
 959  	NULL);
 960  
 961  
 962    /* NON-castable spells should appear below here. */
 963  
 964    spello(SPELL_IDENTIFY, "identify", 0, 0, 0, 0,
 965  	TAR_CHAR_ROOM | TAR_OBJ_INV | TAR_OBJ_ROOM, FALSE, MAG_MANUAL,
 966  	NULL);
 967  
 968    /*
 969     * These spells are currently not used, not implemented, and not castable.
 970     * Values for the 'breath' spells are filled in assuming a dragon's breath.
 971     */
 972  
 973    spello(SPELL_FIRE_BREATH, "fire breath", 0, 0, 0, POS_SITTING,
 974  	TAR_IGNORE, TRUE, 0,
 975  	NULL);
 976  
 977    spello(SPELL_GAS_BREATH, "gas breath", 0, 0, 0, POS_SITTING,
 978  	TAR_IGNORE, TRUE, 0,
 979  	NULL);
 980  
 981    spello(SPELL_FROST_BREATH, "frost breath", 0, 0, 0, POS_SITTING,
 982  	TAR_IGNORE, TRUE, 0,
 983  	NULL);
 984  
 985    spello(SPELL_ACID_BREATH, "acid breath", 0, 0, 0, POS_SITTING,
 986  	TAR_IGNORE, TRUE, 0,
 987  	NULL);
 988  
 989    spello(SPELL_LIGHTNING_BREATH, "lightning breath", 0, 0, 0, POS_SITTING,
 990  	TAR_IGNORE, TRUE, 0,
 991  	NULL);
 992  
 993    /*
 994     * Declaration of skills - this actually doesn't do anything except
 995     * set it up so that immortals can use these skills by default.  The
 996     * min level to use the skill for other classes is set up in class.c.
 997     */
 998  
 999    skillo(SKILL_BACKSTAB, "backstab");
1000    skillo(SKILL_BASH, "bash");
1001    skillo(SKILL_HIDE, "hide");
1002    skillo(SKILL_KICK, "kick");
1003    skillo(SKILL_PICK_LOCK, "pick lock");
1004    skillo(SKILL_RESCUE, "rescue");
1005    skillo(SKILL_SNEAK, "sneak");
1006    skillo(SKILL_STEAL, "steal");
1007    skillo(SKILL_TRACK, "track");
1008  }
1009