/ circle3.1 / src / magic.c
magic.c
  1  /* ************************************************************************
  2  *   File: magic.c                                       Part of CircleMUD *
  3  *  Usage: low-level functions for magic; spell template code              *
  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  #include "structs.h"
 16  #include "utils.h"
 17  #include "comm.h"
 18  #include "spells.h"
 19  #include "handler.h"
 20  #include "db.h"
 21  #include "interpreter.h"
 22  #include "constants.h"
 23  
 24  
 25  /* external variables */
 26  extern int mini_mud;
 27  extern int pk_allowed;
 28  extern struct spell_info_type spell_info[];
 29  
 30  /* external functions */
 31  byte saving_throws(int class_num, int type, int level); /* class.c */
 32  void clearMemory(struct char_data *ch);
 33  void weight_change_object(struct obj_data *obj, int weight);
 34  
 35  /* local functions */
 36  int mag_materials(struct char_data *ch, int item0, int item1, int item2, int extract, int verbose);
 37  void perform_mag_groups(int level, struct char_data *ch, struct char_data *tch, int spellnum, int savetype);
 38  int mag_savingthrow(struct char_data *ch, int type, int modifier);
 39  void affect_update(void);
 40  
 41  /*
 42   * Saving throws are now in class.c as of bpl13.
 43   */
 44  
 45  
 46  /*
 47   * Negative apply_saving_throw[] values make saving throws better!
 48   * Then, so do negative modifiers.  Though people may be used to
 49   * the reverse of that. It's due to the code modifying the target
 50   * saving throw instead of the random number of the character as
 51   * in some other systems.
 52   */
 53  int mag_savingthrow(struct char_data *ch, int type, int modifier)
 54  {
 55    /* NPCs use warrior tables according to some book */
 56    int class_sav = CLASS_WARRIOR;
 57    int save;
 58  
 59    if (!IS_NPC(ch))
 60      class_sav = GET_CLASS(ch);
 61  
 62    save = saving_throws(class_sav, type, GET_LEVEL(ch));
 63    save += GET_SAVE(ch, type);
 64    save += modifier;
 65  
 66    /* Throwing a 0 is always a failure. */
 67    if (MAX(1, save) < rand_number(0, 99))
 68      return (TRUE);
 69  
 70    /* Oops, failed. Sorry. */
 71    return (FALSE);
 72  }
 73  
 74  
 75  /* affect_update: called from comm.c (causes spells to wear off) */
 76  void affect_update(void)
 77  {
 78    struct affected_type *af, *next;
 79    struct char_data *i;
 80  
 81    for (i = character_list; i; i = i->next)
 82      for (af = i->affected; af; af = next) {
 83        next = af->next;
 84        if (af->duration >= 1)
 85  	af->duration--;
 86        else if (af->duration == -1)	/* No action */
 87  	af->duration = -1;	/* GODs only! unlimited */
 88        else {
 89  	if ((af->type > 0) && (af->type <= MAX_SPELLS))
 90  	  if (!af->next || (af->next->type != af->type) ||
 91  	      (af->next->duration > 0))
 92  	    if (spell_info[af->type].wear_off_msg)
 93  	      send_to_char(i, "%s\r\n", spell_info[af->type].wear_off_msg);
 94  	affect_remove(i, af);
 95        }
 96      }
 97  }
 98  
 99  
100  /*
101   *  mag_materials:
102   *  Checks for up to 3 vnums (spell reagents) in the player's inventory.
103   *
104   * No spells implemented in Circle use mag_materials, but you can use
105   * it to implement your own spells which require ingredients (i.e., some
106   * heal spell which requires a rare herb or some such.)
107   */
108  int mag_materials(struct char_data *ch, int item0, int item1, int item2,
109  		      int extract, int verbose)
110  {
111    struct obj_data *tobj;
112    struct obj_data *obj0 = NULL, *obj1 = NULL, *obj2 = NULL;
113  
114    for (tobj = ch->carrying; tobj; tobj = tobj->next_content) {
115      if ((item0 > 0) && (GET_OBJ_VNUM(tobj) == item0)) {
116        obj0 = tobj;
117        item0 = -1;
118      } else if ((item1 > 0) && (GET_OBJ_VNUM(tobj) == item1)) {
119        obj1 = tobj;
120        item1 = -1;
121      } else if ((item2 > 0) && (GET_OBJ_VNUM(tobj) == item2)) {
122        obj2 = tobj;
123        item2 = -1;
124      }
125    }
126    if ((item0 > 0) || (item1 > 0) || (item2 > 0)) {
127      if (verbose) {
128        switch (rand_number(0, 2)) {
129        case 0:
130  	send_to_char(ch, "A wart sprouts on your nose.\r\n");
131  	break;
132        case 1:
133  	send_to_char(ch, "Your hair falls out in clumps.\r\n");
134  	break;
135        case 2:
136  	send_to_char(ch, "A huge corn develops on your big toe.\r\n");
137  	break;
138        }
139      }
140      return (FALSE);
141    }
142    if (extract) {
143      if (item0 < 0)
144        extract_obj(obj0);
145      if (item1 < 0)
146        extract_obj(obj1);
147      if (item2 < 0)
148        extract_obj(obj2);
149    }
150    if (verbose) {
151      send_to_char(ch, "A puff of smoke rises from your pack.\r\n");
152      act("A puff of smoke rises from $n's pack.", TRUE, ch, NULL, NULL, TO_ROOM);
153    }
154    return (TRUE);
155  }
156  
157  
158  
159  
160  /*
161   * Every spell that does damage comes through here.  This calculates the
162   * amount of damage, adds in any modifiers, determines what the saves are,
163   * tests for save and calls damage().
164   *
165   * -1 = dead, otherwise the amount of damage done.
166   */
167  int mag_damage(int level, struct char_data *ch, struct char_data *victim,
168  		     int spellnum, int savetype)
169  {
170    int dam = 0;
171  
172    if (victim == NULL || ch == NULL)
173      return (0);
174  
175    switch (spellnum) {
176      /* Mostly mages */
177    case SPELL_MAGIC_MISSILE:
178    case SPELL_CHILL_TOUCH:	/* chill touch also has an affect */
179      if (IS_MAGIC_USER(ch))
180        dam = dice(1, 8) + 1;
181      else
182        dam = dice(1, 6) + 1;
183      break;
184    case SPELL_BURNING_HANDS:
185      if (IS_MAGIC_USER(ch))
186        dam = dice(3, 8) + 3;
187      else
188        dam = dice(3, 6) + 3;
189      break;
190    case SPELL_SHOCKING_GRASP:
191      if (IS_MAGIC_USER(ch))
192        dam = dice(5, 8) + 5;
193      else
194        dam = dice(5, 6) + 5;
195      break;
196    case SPELL_LIGHTNING_BOLT:
197      if (IS_MAGIC_USER(ch))
198        dam = dice(7, 8) + 7;
199      else
200        dam = dice(7, 6) + 7;
201      break;
202    case SPELL_COLOR_SPRAY:
203      if (IS_MAGIC_USER(ch))
204        dam = dice(9, 8) + 9;
205      else
206        dam = dice(9, 6) + 9;
207      break;
208    case SPELL_FIREBALL:
209      if (IS_MAGIC_USER(ch))
210        dam = dice(11, 8) + 11;
211      else
212        dam = dice(11, 6) + 11;
213      break;
214  
215      /* Mostly clerics */
216    case SPELL_DISPEL_EVIL:
217      dam = dice(6, 8) + 6;
218      if (IS_EVIL(ch)) {
219        victim = ch;
220        dam = GET_HIT(ch) - 1;
221      } else if (IS_GOOD(victim)) {
222        act("The gods protect $N.", FALSE, ch, 0, victim, TO_CHAR);
223        return (0);
224      }
225      break;
226    case SPELL_DISPEL_GOOD:
227      dam = dice(6, 8) + 6;
228      if (IS_GOOD(ch)) {
229        victim = ch;
230        dam = GET_HIT(ch) - 1;
231      } else if (IS_EVIL(victim)) {
232        act("The gods protect $N.", FALSE, ch, 0, victim, TO_CHAR);
233        return (0);
234      }
235      break;
236  
237  
238    case SPELL_CALL_LIGHTNING:
239      dam = dice(7, 8) + 7;
240      break;
241  
242    case SPELL_HARM:
243      dam = dice(8, 8) + 8;
244      break;
245  
246    case SPELL_ENERGY_DRAIN:
247      if (GET_LEVEL(victim) <= 2)
248        dam = 100;
249      else
250        dam = dice(1, 10);
251      break;
252  
253      /* Area spells */
254    case SPELL_EARTHQUAKE:
255      dam = dice(2, 8) + level;
256      break;
257  
258    } /* switch(spellnum) */
259  
260  
261    /* divide damage by two if victim makes his saving throw */
262    if (mag_savingthrow(victim, savetype, 0))
263      dam /= 2;
264  
265    /* and finally, inflict the damage */
266    return (damage(ch, victim, dam, spellnum));
267  }
268  
269  
270  /*
271   * Every spell that does an affect comes through here.  This determines
272   * the effect, whether it is added or replacement, whether it is legal or
273   * not, etc.
274   *
275   * affect_join(vict, aff, add_dur, avg_dur, add_mod, avg_mod)
276   */
277  
278  #define MAX_SPELL_AFFECTS 5	/* change if more needed */
279  
280  void mag_affects(int level, struct char_data *ch, struct char_data *victim,
281  		      int spellnum, int savetype)
282  {
283    struct affected_type af[MAX_SPELL_AFFECTS];
284    bool accum_affect = FALSE, accum_duration = FALSE;
285    const char *to_vict = NULL, *to_room = NULL;
286    int i;
287  
288  
289    if (victim == NULL || ch == NULL)
290      return;
291  
292    for (i = 0; i < MAX_SPELL_AFFECTS; i++) {
293      af[i].type = spellnum;
294      af[i].bitvector = 0;
295      af[i].modifier = 0;
296      af[i].location = APPLY_NONE;
297    }
298  
299    switch (spellnum) {
300  
301    case SPELL_CHILL_TOUCH:
302      af[0].location = APPLY_STR;
303      if (mag_savingthrow(victim, savetype, 0))
304        af[0].duration = 1;
305      else
306        af[0].duration = 4;
307      af[0].modifier = -1;
308      accum_duration = TRUE;
309      to_vict = "You feel your strength wither!";
310      break;
311  
312    case SPELL_ARMOR:
313      af[0].location = APPLY_AC;
314      af[0].modifier = -20;
315      af[0].duration = 24;
316      accum_duration = TRUE;
317      to_vict = "You feel someone protecting you.";
318      break;
319  
320    case SPELL_BLESS:
321      af[0].location = APPLY_HITROLL;
322      af[0].modifier = 2;
323      af[0].duration = 6;
324  
325      af[1].location = APPLY_SAVING_SPELL;
326      af[1].modifier = -1;
327      af[1].duration = 6;
328  
329      accum_duration = TRUE;
330      to_vict = "You feel righteous.";
331      break;
332  
333    case SPELL_BLINDNESS:
334      if (MOB_FLAGGED(victim,MOB_NOBLIND) || mag_savingthrow(victim, savetype, 0)) {
335        send_to_char(ch, "You fail.\r\n");
336        return;
337      }
338  
339      af[0].location = APPLY_HITROLL;
340      af[0].modifier = -4;
341      af[0].duration = 2;
342      af[0].bitvector = AFF_BLIND;
343  
344      af[1].location = APPLY_AC;
345      af[1].modifier = 40;
346      af[1].duration = 2;
347      af[1].bitvector = AFF_BLIND;
348  
349      to_room = "$n seems to be blinded!";
350      to_vict = "You have been blinded!";
351      break;
352  
353    case SPELL_CURSE:
354      if (mag_savingthrow(victim, savetype, 0)) {
355        send_to_char(ch, "%s", NOEFFECT);
356        return;
357      }
358  
359      af[0].location = APPLY_HITROLL;
360      af[0].duration = 1 + (GET_LEVEL(ch) / 2);
361      af[0].modifier = -1;
362      af[0].bitvector = AFF_CURSE;
363  
364      af[1].location = APPLY_DAMROLL;
365      af[1].duration = 1 + (GET_LEVEL(ch) / 2);
366      af[1].modifier = -1;
367      af[1].bitvector = AFF_CURSE;
368  
369      accum_duration = TRUE;
370      accum_affect = TRUE;
371      to_room = "$n briefly glows red!";
372      to_vict = "You feel very uncomfortable.";
373      break;
374  
375    case SPELL_DETECT_ALIGN:
376      af[0].duration = 12 + level;
377      af[0].bitvector = AFF_DETECT_ALIGN;
378      accum_duration = TRUE;
379      to_vict = "Your eyes tingle.";
380      break;
381  
382    case SPELL_DETECT_INVIS:
383      af[0].duration = 12 + level;
384      af[0].bitvector = AFF_DETECT_INVIS;
385      accum_duration = TRUE;
386      to_vict = "Your eyes tingle.";
387      break;
388  
389    case SPELL_DETECT_MAGIC:
390      af[0].duration = 12 + level;
391      af[0].bitvector = AFF_DETECT_MAGIC;
392      accum_duration = TRUE;
393      to_vict = "Your eyes tingle.";
394      break;
395  
396    case SPELL_INFRAVISION:
397      af[0].duration = 12 + level;
398      af[0].bitvector = AFF_INFRAVISION;
399      accum_duration = TRUE;
400      to_vict = "Your eyes glow red.";
401      to_room = "$n's eyes glow red.";
402      break;
403  
404    case SPELL_INVISIBLE:
405      if (!victim)
406        victim = ch;
407  
408      af[0].duration = 12 + (GET_LEVEL(ch) / 4);
409      af[0].modifier = -40;
410      af[0].location = APPLY_AC;
411      af[0].bitvector = AFF_INVISIBLE;
412      accum_duration = TRUE;
413      to_vict = "You vanish.";
414      to_room = "$n slowly fades out of existence.";
415      break;
416  
417    case SPELL_POISON:
418      if (mag_savingthrow(victim, savetype, 0)) {
419        send_to_char(ch, "%s", NOEFFECT);
420        return;
421      }
422  
423      af[0].location = APPLY_STR;
424      af[0].duration = GET_LEVEL(ch);
425      af[0].modifier = -2;
426      af[0].bitvector = AFF_POISON;
427      to_vict = "You feel very sick.";
428      to_room = "$n gets violently ill!";
429      break;
430  
431    case SPELL_PROT_FROM_EVIL:
432      af[0].duration = 24;
433      af[0].bitvector = AFF_PROTECT_EVIL;
434      accum_duration = TRUE;
435      to_vict = "You feel invulnerable!";
436      break;
437  
438    case SPELL_SANCTUARY:
439      af[0].duration = 4;
440      af[0].bitvector = AFF_SANCTUARY;
441  
442      accum_duration = TRUE;
443      to_vict = "A white aura momentarily surrounds you.";
444      to_room = "$n is surrounded by a white aura.";
445      break;
446  
447    case SPELL_SLEEP:
448      if (!pk_allowed && !IS_NPC(ch) && !IS_NPC(victim))
449        return;
450      if (MOB_FLAGGED(victim, MOB_NOSLEEP))
451        return;
452      if (mag_savingthrow(victim, savetype, 0))
453        return;
454  
455      af[0].duration = 4 + (GET_LEVEL(ch) / 4);
456      af[0].bitvector = AFF_SLEEP;
457  
458      if (GET_POS(victim) > POS_SLEEPING) {
459        send_to_char(victim, "You feel very sleepy...  Zzzz......\r\n");
460        act("$n goes to sleep.", TRUE, victim, 0, 0, TO_ROOM);
461        GET_POS(victim) = POS_SLEEPING;
462      }
463      break;
464  
465    case SPELL_STRENGTH:
466      if (GET_ADD(victim) == 100)
467        return;
468  
469      af[0].location = APPLY_STR;
470      af[0].duration = (GET_LEVEL(ch) / 2) + 4;
471      af[0].modifier = 1 + (level > 18);
472      accum_duration = TRUE;
473      accum_affect = TRUE;
474      to_vict = "You feel stronger!";
475      break;
476  
477    case SPELL_SENSE_LIFE:
478      to_vict = "Your feel your awareness improve.";
479      af[0].duration = GET_LEVEL(ch);
480      af[0].bitvector = AFF_SENSE_LIFE;
481      accum_duration = TRUE;
482      break;
483  
484    case SPELL_WATERWALK:
485      af[0].duration = 24;
486      af[0].bitvector = AFF_WATERWALK;
487      accum_duration = TRUE;
488      to_vict = "You feel webbing between your toes.";
489      break;
490    }
491  
492    /*
493     * If this is a mob that has this affect set in its mob file, do not
494     * perform the affect.  This prevents people from un-sancting mobs
495     * by sancting them and waiting for it to fade, for example.
496     */
497    if (IS_NPC(victim) && !affected_by_spell(victim, spellnum))
498      for (i = 0; i < MAX_SPELL_AFFECTS; i++)
499        if (AFF_FLAGGED(victim, af[i].bitvector)) {
500  	send_to_char(ch, "%s", NOEFFECT);
501  	return;
502        }
503  
504    /*
505     * If the victim is already affected by this spell, and the spell does
506     * not have an accumulative effect, then fail the spell.
507     */
508    if (affected_by_spell(victim,spellnum) && !(accum_duration||accum_affect)) {
509      send_to_char(ch, "%s", NOEFFECT);
510      return;
511    }
512  
513    for (i = 0; i < MAX_SPELL_AFFECTS; i++)
514      if (af[i].bitvector || (af[i].location != APPLY_NONE))
515        affect_join(victim, af+i, accum_duration, FALSE, accum_affect, FALSE);
516  
517    if (to_vict != NULL)
518      act(to_vict, FALSE, victim, 0, ch, TO_CHAR);
519    if (to_room != NULL)
520      act(to_room, TRUE, victim, 0, ch, TO_ROOM);
521  }
522  
523  
524  /*
525   * This function is used to provide services to mag_groups.  This function
526   * is the one you should change to add new group spells.
527   */
528  void perform_mag_groups(int level, struct char_data *ch,
529  			struct char_data *tch, int spellnum, int savetype)
530  {
531    switch (spellnum) {
532      case SPELL_GROUP_HEAL:
533      mag_points(level, ch, tch, SPELL_HEAL, savetype);
534      break;
535    case SPELL_GROUP_ARMOR:
536      mag_affects(level, ch, tch, SPELL_ARMOR, savetype);
537      break;
538    case SPELL_GROUP_RECALL:
539      spell_recall(level, ch, tch, NULL);
540      break;
541    }
542  }
543  
544  
545  /*
546   * Every spell that affects the group should run through here
547   * perform_mag_groups contains the switch statement to send us to the right
548   * magic.
549   *
550   * group spells affect everyone grouped with the caster who is in the room,
551   * caster last.
552   *
553   * To add new group spells, you shouldn't have to change anything in
554   * mag_groups -- just add a new case to perform_mag_groups.
555   */
556  void mag_groups(int level, struct char_data *ch, int spellnum, int savetype)
557  {
558    struct char_data *tch, *k;
559    struct follow_type *f, *f_next;
560  
561    if (ch == NULL)
562      return;
563  
564    if (!AFF_FLAGGED(ch, AFF_GROUP))
565      return;
566    if (ch->master != NULL)
567      k = ch->master;
568    else
569      k = ch;
570    for (f = k->followers; f; f = f_next) {
571      f_next = f->next;
572      tch = f->follower;
573      if (IN_ROOM(tch) != IN_ROOM(ch))
574        continue;
575      if (!AFF_FLAGGED(tch, AFF_GROUP))
576        continue;
577      if (ch == tch)
578        continue;
579      perform_mag_groups(level, ch, tch, spellnum, savetype);
580    }
581  
582    if ((k != ch) && AFF_FLAGGED(k, AFF_GROUP))
583      perform_mag_groups(level, ch, k, spellnum, savetype);
584    perform_mag_groups(level, ch, ch, spellnum, savetype);
585  }
586  
587  
588  /*
589   * mass spells affect every creature in the room except the caster.
590   *
591   * No spells of this class currently implemented.
592   */
593  void mag_masses(int level, struct char_data *ch, int spellnum, int savetype)
594  {
595    struct char_data *tch, *tch_next;
596  
597    for (tch = world[IN_ROOM(ch)].people; tch; tch = tch_next) {
598      tch_next = tch->next_in_room;
599      if (tch == ch)
600        continue;
601  
602      switch (spellnum) {
603      }
604    }
605  }
606  
607  
608  /*
609   * Every spell that affects an area (room) runs through here.  These are
610   * generally offensive spells.  This calls mag_damage to do the actual
611   * damage -- all spells listed here must also have a case in mag_damage()
612   * in order for them to work.
613   *
614   *  area spells have limited targets within the room.
615   */
616  void mag_areas(int level, struct char_data *ch, int spellnum, int savetype)
617  {
618    struct char_data *tch, *next_tch;
619    const char *to_char = NULL, *to_room = NULL;
620  
621    if (ch == NULL)
622      return;
623  
624    /*
625     * to add spells to this fn, just add the message here plus an entry
626     * in mag_damage for the damaging part of the spell.
627     */
628    switch (spellnum) {
629    case SPELL_EARTHQUAKE:
630      to_char = "You gesture and the earth begins to shake all around you!";
631      to_room ="$n gracefully gestures and the earth begins to shake violently!";
632      break;
633    }
634  
635    if (to_char != NULL)
636      act(to_char, FALSE, ch, 0, 0, TO_CHAR);
637    if (to_room != NULL)
638      act(to_room, FALSE, ch, 0, 0, TO_ROOM);
639    
640  
641    for (tch = world[IN_ROOM(ch)].people; tch; tch = next_tch) {
642      next_tch = tch->next_in_room;
643  
644      /*
645       * The skips: 1: the caster
646       *            2: immortals
647       *            3: if no pk on this mud, skips over all players
648       *            4: pets (charmed NPCs)
649       */
650  
651      if (tch == ch)
652        continue;
653      if (!IS_NPC(tch) && GET_LEVEL(tch) >= LVL_IMMORT)
654        continue;
655      if (!pk_allowed && !IS_NPC(ch) && !IS_NPC(tch))
656        continue;
657      if (!IS_NPC(ch) && IS_NPC(tch) && AFF_FLAGGED(tch, AFF_CHARM))
658        continue;
659  
660      /* Doesn't matter if they die here so we don't check. -gg 6/24/98 */
661      mag_damage(level, ch, tch, spellnum, 1);
662    }
663  }
664  
665  
666  /*
667   *  Every spell which summons/gates/conjours a mob comes through here.
668   *
669   *  None of these spells are currently implemented in CircleMUD; these
670   *  were taken as examples from the JediMUD code.  Summons can be used
671   *  for spells like clone, ariel servant, etc.
672   *
673   * 10/15/97 (gg) - Implemented Animate Dead and Clone.
674   */
675  
676  /*
677   * These use act(), don't put the \r\n.
678   */
679  const char *mag_summon_msgs[] = {
680    "\r\n",
681    "$n makes a strange magical gesture; you feel a strong breeze!",
682    "$n animates a corpse!",
683    "$N appears from a cloud of thick blue smoke!",
684    "$N appears from a cloud of thick green smoke!",
685    "$N appears from a cloud of thick red smoke!",
686    "$N disappears in a thick black cloud!"
687    "As $n makes a strange magical gesture, you feel a strong breeze.",
688    "As $n makes a strange magical gesture, you feel a searing heat.",
689    "As $n makes a strange magical gesture, you feel a sudden chill.",
690    "As $n makes a strange magical gesture, you feel the dust swirl.",
691    "$n magically divides!",
692    "$n animates a corpse!"
693  };
694  
695  /*
696   * Keep the \r\n because these use send_to_char.
697   */
698  const char *mag_summon_fail_msgs[] = {
699    "\r\n",
700    "There are no such creatures.\r\n",
701    "Uh oh...\r\n",
702    "Oh dear.\r\n",
703    "Gosh durnit!\r\n",
704    "The elements resist!\r\n",
705    "You failed.\r\n",
706    "There is no corpse!\r\n"
707  };
708  
709  /* These mobiles do not exist. */
710  #define MOB_MONSUM_I		130
711  #define MOB_MONSUM_II		140
712  #define MOB_MONSUM_III		150
713  #define MOB_GATE_I		160
714  #define MOB_GATE_II		170
715  #define MOB_GATE_III		180
716  
717  /* Defined mobiles. */
718  #define MOB_ELEMENTAL_BASE	20	/* Only one for now. */
719  #define MOB_CLONE		10
720  #define MOB_ZOMBIE		11
721  #define MOB_AERIALSERVANT	19
722  
723  
724  void mag_summons(int level, struct char_data *ch, struct obj_data *obj,
725  		      int spellnum, int savetype)
726  {
727    struct char_data *mob = NULL;
728    struct obj_data *tobj, *next_obj;
729    int pfail = 0, msg = 0, fmsg = 0, num = 1, handle_corpse = FALSE, i;
730    mob_vnum mob_num;
731  
732    if (ch == NULL)
733      return;
734  
735    switch (spellnum) {
736    case SPELL_CLONE:
737      msg = 10;
738      fmsg = rand_number(2, 6);	/* Random fail message. */
739      mob_num = MOB_CLONE;
740      pfail = 50;	/* 50% failure, should be based on something later. */
741      break;
742  
743    case SPELL_ANIMATE_DEAD:
744      if (obj == NULL || !IS_CORPSE(obj)) {
745        act(mag_summon_fail_msgs[7], FALSE, ch, 0, 0, TO_CHAR);
746        return;
747      }
748      handle_corpse = TRUE;
749      msg = 11;
750      fmsg = rand_number(2, 6);	/* Random fail message. */
751      mob_num = MOB_ZOMBIE;
752      pfail = 10;	/* 10% failure, should vary in the future. */
753      break;
754  
755    default:
756      return;
757    }
758  
759    if (AFF_FLAGGED(ch, AFF_CHARM)) {
760      send_to_char(ch, "You are too giddy to have any followers!\r\n");
761      return;
762    }
763    if (rand_number(0, 101) < pfail) {
764      send_to_char(ch, "%s", mag_summon_fail_msgs[fmsg]);
765      return;
766    }
767    for (i = 0; i < num; i++) {
768      if (!(mob = read_mobile(mob_num, VIRTUAL))) {
769        send_to_char(ch, "You don't quite remember how to make that creature.\r\n");
770        return;
771      }
772      char_to_room(mob, IN_ROOM(ch));
773      IS_CARRYING_W(mob) = 0;
774      IS_CARRYING_N(mob) = 0;
775      SET_BIT(AFF_FLAGS(mob), AFF_CHARM);
776      if (spellnum == SPELL_CLONE) {
777        /* Don't mess up the prototype; use new string copies. */
778        mob->player.name = strdup(GET_NAME(ch));
779        mob->player.short_descr = strdup(GET_NAME(ch));
780      }
781      act(mag_summon_msgs[msg], FALSE, ch, 0, mob, TO_ROOM);
782      add_follower(mob, ch);
783    }
784    if (handle_corpse) {
785      for (tobj = obj->contains; tobj; tobj = next_obj) {
786        next_obj = tobj->next_content;
787        obj_from_obj(tobj);
788        obj_to_char(tobj, mob);
789      }
790      extract_obj(obj);
791    }
792  }
793  
794  
795  void mag_points(int level, struct char_data *ch, struct char_data *victim,
796  		     int spellnum, int savetype)
797  {
798    int healing = 0, move = 0;
799  
800    if (victim == NULL)
801      return;
802  
803    switch (spellnum) {
804    case SPELL_CURE_LIGHT:
805      healing = dice(1, 8) + 1 + (level / 4);
806      send_to_char(victim, "You feel better.\r\n");
807      break;
808    case SPELL_CURE_CRITIC:
809      healing = dice(3, 8) + 3 + (level / 4);
810      send_to_char(victim, "You feel a lot better!\r\n");
811      break;
812    case SPELL_HEAL:
813      healing = 100 + dice(3, 8);
814      send_to_char(victim, "A warm feeling floods your body.\r\n");
815      break;
816    }
817    GET_HIT(victim) = MIN(GET_MAX_HIT(victim), GET_HIT(victim) + healing);
818    GET_MOVE(victim) = MIN(GET_MAX_MOVE(victim), GET_MOVE(victim) + move);
819    update_pos(victim);
820  }
821  
822  
823  void mag_unaffects(int level, struct char_data *ch, struct char_data *victim,
824  		        int spellnum, int type)
825  {
826    int spell = 0, msg_not_affected = TRUE;
827    const char *to_vict = NULL, *to_room = NULL;
828  
829    if (victim == NULL)
830      return;
831  
832    switch (spellnum) {
833    case SPELL_HEAL:
834      /*
835       * Heal also restores health, so don't give the "no effect" message
836       * if the target isn't afflicted by the 'blindness' spell.
837       */
838      msg_not_affected = FALSE;
839      /* fall-through */
840    case SPELL_CURE_BLIND:
841      spell = SPELL_BLINDNESS;
842      to_vict = "Your vision returns!";
843      to_room = "There's a momentary gleam in $n's eyes.";
844      break;
845    case SPELL_REMOVE_POISON:
846      spell = SPELL_POISON;
847      to_vict = "A warm feeling runs through your body!";
848      to_room = "$n looks better.";
849      break;
850    case SPELL_REMOVE_CURSE:
851      spell = SPELL_CURSE;
852      to_vict = "You don't feel so unlucky.";
853      break;
854    default:
855      log("SYSERR: unknown spellnum %d passed to mag_unaffects.", spellnum);
856      return;
857    }
858  
859    if (!affected_by_spell(victim, spell)) {
860      if (msg_not_affected)
861        send_to_char(ch, "%s", NOEFFECT);
862      return;
863    }
864  
865    affect_from_char(victim, spell);
866    if (to_vict != NULL)
867      act(to_vict, FALSE, victim, 0, ch, TO_CHAR);
868    if (to_room != NULL)
869      act(to_room, TRUE, victim, 0, ch, TO_ROOM);
870  
871  }
872  
873  
874  void mag_alter_objs(int level, struct char_data *ch, struct obj_data *obj,
875  		         int spellnum, int savetype)
876  {
877    const char *to_char = NULL, *to_room = NULL;
878  
879    if (obj == NULL)
880      return;
881  
882    switch (spellnum) {
883      case SPELL_BLESS:
884        if (!OBJ_FLAGGED(obj, ITEM_BLESS) &&
885  	  (GET_OBJ_WEIGHT(obj) <= 5 * GET_LEVEL(ch))) {
886  	SET_BIT(GET_OBJ_EXTRA(obj), ITEM_BLESS);
887  	to_char = "$p glows briefly.";
888        }
889        break;
890      case SPELL_CURSE:
891        if (!OBJ_FLAGGED(obj, ITEM_NODROP)) {
892  	SET_BIT(GET_OBJ_EXTRA(obj), ITEM_NODROP);
893  	if (GET_OBJ_TYPE(obj) == ITEM_WEAPON)
894  	  GET_OBJ_VAL(obj, 2)--;
895  	to_char = "$p briefly glows red.";
896        }
897        break;
898      case SPELL_INVISIBLE:
899        if (!OBJ_FLAGGED(obj, ITEM_NOINVIS | ITEM_INVISIBLE)) {
900          SET_BIT(GET_OBJ_EXTRA(obj), ITEM_INVISIBLE);
901          to_char = "$p vanishes.";
902        }
903        break;
904      case SPELL_POISON:
905        if (((GET_OBJ_TYPE(obj) == ITEM_DRINKCON) ||
906           (GET_OBJ_TYPE(obj) == ITEM_FOUNTAIN) ||
907           (GET_OBJ_TYPE(obj) == ITEM_FOOD)) && !GET_OBJ_VAL(obj, 3)) {
908        GET_OBJ_VAL(obj, 3) = 1;
909        to_char = "$p steams briefly.";
910        }
911        break;
912      case SPELL_REMOVE_CURSE:
913        if (OBJ_FLAGGED(obj, ITEM_NODROP)) {
914          REMOVE_BIT(GET_OBJ_EXTRA(obj), ITEM_NODROP);
915          if (GET_OBJ_TYPE(obj) == ITEM_WEAPON)
916            GET_OBJ_VAL(obj, 2)++;
917          to_char = "$p briefly glows blue.";
918        }
919        break;
920      case SPELL_REMOVE_POISON:
921        if (((GET_OBJ_TYPE(obj) == ITEM_DRINKCON) ||
922           (GET_OBJ_TYPE(obj) == ITEM_FOUNTAIN) ||
923           (GET_OBJ_TYPE(obj) == ITEM_FOOD)) && GET_OBJ_VAL(obj, 3)) {
924          GET_OBJ_VAL(obj, 3) = 0;
925          to_char = "$p steams briefly.";
926        }
927        break;
928    }
929  
930    if (to_char == NULL)
931      send_to_char(ch, "%s", NOEFFECT);
932    else
933      act(to_char, TRUE, ch, obj, 0, TO_CHAR);
934  
935    if (to_room != NULL)
936      act(to_room, TRUE, ch, obj, 0, TO_ROOM);
937    else if (to_char != NULL)
938      act(to_char, TRUE, ch, obj, 0, TO_ROOM);
939  
940  }
941  
942  
943  
944  void mag_creations(int level, struct char_data *ch, int spellnum)
945  {
946    struct obj_data *tobj;
947    obj_vnum z;
948  
949    if (ch == NULL)
950      return;
951    /* level = MAX(MIN(level, LVL_IMPL), 1); - Hm, not used. */
952  
953    switch (spellnum) {
954    case SPELL_CREATE_FOOD:
955      z = 10;
956      break;
957    default:
958      send_to_char(ch, "Spell unimplemented, it would seem.\r\n");
959      return;
960    }
961  
962    if (!(tobj = read_object(z, VIRTUAL))) {
963      send_to_char(ch, "I seem to have goofed.\r\n");
964      log("SYSERR: spell_creations, spell %d, obj %d: obj not found",
965  	    spellnum, z);
966      return;
967    }
968    obj_to_char(tobj, ch);
969    act("$n creates $p.", FALSE, ch, tobj, 0, TO_ROOM);
970    act("You create $p.", FALSE, ch, tobj, 0, TO_CHAR);
971  }
972