Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

magic.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
00003  *  Michael Seifert, Hans Henrik Strfeldt, Tom Madsen, and Katja Nyboe.    *
00004  *                                                                         *
00005  *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
00006  *  Chastain, Michael Quan, and Mitchell Tse.                              *
00007  *                                                                         *
00008  *  In order to use any part of this Merc Diku Mud, you must comply with   *
00009  *  both the original Diku license in 'license.doc' as well the Merc       *
00010  *  license in 'license.txt'.  In particular, you may not remove either of *
00011  *  these copyright notices.                                               *
00012  *                                                                         *
00013  *  Much time and thought has gone into this software and you are          *
00014  *  benefitting.  We hope that you share your changes too.  What goes      *
00015  *  around, comes around.                                                  *
00016  ***************************************************************************/
00017 
00018 /***************************************************************************
00019  *  ROM 2.4 is copyright 1993-1998 Russ Taylor                             *
00020  *  ROM has been brought to you by the ROM consortium                      *
00021  *      Russ Taylor (rtaylor@hypercube.org)                                *
00022  *      Gabrielle Taylor (gtaylor@hypercube.org)                           *
00023  *      Brian Moore (zump@rom.org)                                         *
00024  *  By using this code, you have agreed to follow the terms of the         *
00025  *  ROM license, in the file Rom24/doc/rom.license                         *
00026  ***************************************************************************/
00027 
00028 
00029 #if defined(macintosh)
00030 #include <types.h>
00031 #else
00032 #include <sys/types.h>
00033 #endif
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include <string.h>
00037 #include <time.h>
00038 #include "merc.h"
00039 #include "interp.h"
00040 #include "magic.h"
00041 #include "recycle.h"
00042 
00043 /*
00044  * Local functions.
00045  */
00046 void say_spell args ((CHAR_DATA * ch, int sn));
00047 
00048 /* imported functions */
00049 bool remove_obj args ((CHAR_DATA * ch, int iWear, bool fReplace));
00050 void wear_obj args ((CHAR_DATA * ch, OBJ_DATA * obj, bool fReplace));
00051 
00052 
00053 
00054 /*
00055  * Lookup a skill by name.
00056  */
00057 int skill_lookup (const char *name)
00058 {
00059     int sn;
00060 
00061     for (sn = 0; sn < MAX_SKILL; sn++)
00062     {
00063         if (skill_table[sn].name == NULL)
00064             break;
00065         if (LOWER (name[0]) == LOWER (skill_table[sn].name[0])
00066             && !str_prefix (name, skill_table[sn].name))
00067             return sn;
00068     }
00069 
00070     return -1;
00071 }
00072 
00073 int find_spell (CHAR_DATA * ch, const char *name)
00074 {
00075     /* finds a spell the character can cast if possible */
00076     int sn, found = -1;
00077 
00078     if (IS_NPC (ch))
00079         return skill_lookup (name);
00080 
00081     for (sn = 0; sn < MAX_SKILL; sn++)
00082     {
00083         if (skill_table[sn].name == NULL)
00084             break;
00085         if (LOWER (name[0]) == LOWER (skill_table[sn].name[0])
00086             && !str_prefix (name, skill_table[sn].name))
00087         {
00088             if (found == -1)
00089                 found = sn;
00090             if (ch->level >= skill_table[sn].skill_level[ch->class]
00091                 && ch->pcdata->learned[sn] > 0)
00092                 return sn;
00093         }
00094     }
00095     return found;
00096 }
00097 
00098 
00099 
00100 /*
00101  * Lookup a skill by slot number.
00102  * Used for object loading.
00103  */
00104 int slot_lookup (int slot)
00105 {
00106     extern bool fBootDb;
00107     int sn;
00108 
00109     if (slot <= 0)
00110         return -1;
00111 
00112     for (sn = 0; sn < MAX_SKILL; sn++)
00113     {
00114         if (slot == skill_table[sn].slot)
00115             return sn;
00116     }
00117 
00118     if (fBootDb)
00119     {
00120         bug ("Slot_lookup: bad slot %d.", slot);
00121         abort ();
00122     }
00123 
00124     return -1;
00125 }
00126 
00127 
00128 
00129 /*
00130  * Utter mystical words for an sn.
00131  */
00132 void say_spell (CHAR_DATA * ch, int sn)
00133 {
00134     char buf[MAX_STRING_LENGTH];
00135     char buf2[MAX_STRING_LENGTH];
00136     CHAR_DATA *rch;
00137     char *pName;
00138     int iSyl;
00139     int length;
00140 
00141     struct syl_type {
00142         char *old;
00143         char *new;
00144     };
00145 
00146     static const struct syl_type syl_table[] = {
00147         {" ", " "},
00148         {"ar", "abra"},
00149         {"au", "kada"},
00150         {"bless", "fido"},
00151         {"blind", "nose"},
00152         {"bur", "mosa"},
00153         {"cu", "judi"},
00154         {"de", "oculo"},
00155         {"en", "unso"},
00156         {"light", "dies"},
00157         {"lo", "hi"},
00158         {"mor", "zak"},
00159         {"move", "sido"},
00160         {"ness", "lacri"},
00161         {"ning", "illa"},
00162         {"per", "duda"},
00163         {"ra", "gru"},
00164         {"fresh", "ima"},
00165         {"re", "candus"},
00166         {"son", "sabru"},
00167         {"tect", "infra"},
00168         {"tri", "cula"},
00169         {"ven", "nofo"},
00170         {"a", "a"}, {"b", "b"}, {"c", "q"}, {"d", "e"},
00171         {"e", "z"}, {"f", "y"}, {"g", "o"}, {"h", "p"},
00172         {"i", "u"}, {"j", "y"}, {"k", "t"}, {"l", "r"},
00173         {"m", "w"}, {"n", "i"}, {"o", "a"}, {"p", "s"},
00174         {"q", "d"}, {"r", "f"}, {"s", "g"}, {"t", "h"},
00175         {"u", "j"}, {"v", "z"}, {"w", "x"}, {"x", "n"},
00176         {"y", "l"}, {"z", "k"},
00177         {"", ""}
00178     };
00179 
00180     buf[0] = '\0';
00181     for (pName = skill_table[sn].name; *pName != '\0'; pName += length)
00182     {
00183         for (iSyl = 0; (length = strlen (syl_table[iSyl].old)) != 0; iSyl++)
00184         {
00185             if (!str_prefix (syl_table[iSyl].old, pName))
00186             {
00187                 strcat (buf, syl_table[iSyl].new);
00188                 break;
00189             }
00190         }
00191 
00192         if (length == 0)
00193             length = 1;
00194     }
00195 
00196     sprintf (buf2, "$n utters the words, '%s'.", buf);
00197     sprintf (buf, "$n utters the words, '%s'.", skill_table[sn].name);
00198 
00199     for (rch = ch->in_room->people; rch; rch = rch->next_in_room)
00200     {
00201         if (rch != ch)
00202             act ((!IS_NPC (rch) && ch->class == rch->class) ? buf : buf2,
00203                  ch, NULL, rch, TO_VICT);
00204     }
00205 
00206     return;
00207 }
00208 
00209 
00210 
00211 /*
00212  * Compute a saving throw.
00213  * Negative apply's make saving throw better.
00214  */
00215 bool saves_spell (int level, CHAR_DATA * victim, int dam_type)
00216 {
00217     int save;
00218 
00219     save = 50 + (victim->level - level) * 5 - victim->saving_throw * 2;
00220     //if (IS_AFFECTED (victim, AFF_BERSERK))
00221     //    save += victim->level / 2;
00222 
00223     switch (check_immune (victim, dam_type))
00224     {
00225         case IS_IMMUNE:
00226             return TRUE;
00227         case IS_RESISTANT:
00228             save += 2;
00229             break;
00230         case IS_VULNERABLE:
00231             save -= 2;
00232             break;
00233     }
00234 
00235     if (!IS_NPC (victim) && class_table[victim->class].fMana)
00236         save = 9 * save / 10;
00237     save = URANGE (5, save, 95);
00238    //char buf[MAX_STRING_LENGTH];
00239    // sprintf(buf, "%d - saving throw\n\r", save);
00240    // send_to_char(buf,victim);
00241     return number_percent () < save;
00242 }
00243 
00244 /* RT save for dispels */
00245 
00246 bool saves_dispel (int dis_level, int spell_level, int duration)
00247 {
00248     int save;
00249 
00250     if (duration == -1)
00251         spell_level += 5;
00252     /* very hard to dispel permanent effects */
00253 
00254     save = 50 + (spell_level - dis_level) * 5;
00255     save = URANGE (5, save, 95);
00256     //rintf_to_char(victim, "%d (dispell) save throw", save);
00257     
00258     return number_percent () < save;
00259 }
00260 
00261 /* co-routine for dispel magic and cancellation */
00262 
00263 bool check_dispel (int dis_level, CHAR_DATA * victim, int sn)
00264 {
00265     AFFECT_DATA *af;
00266 
00267     if (is_affected (victim, sn))
00268     {
00269         for (af = victim->affected; af != NULL; af = af->next)
00270         {
00271             if (af->type == sn)
00272             {
00273                 if (!saves_dispel (dis_level, af->level, af->duration))
00274                 {
00275                     affect_strip (victim, sn);
00276                     if (skill_table[sn].msg_off)
00277                     {
00278                         send_to_char (skill_table[sn].msg_off, victim);
00279                         send_to_char ("\n\r", victim);
00280                     }
00281                     return TRUE;
00282                 }
00283                 else
00284                     af->level--;
00285             }
00286         }
00287     }
00288     return FALSE;
00289 }
00290 
00291 /* for finding mana costs -- temporary version */
00292 int mana_cost (CHAR_DATA * ch, int min_mana, int level)
00293 {
00294     if (ch->level + 2 == level)
00295         return 1000;
00296     return UMAX (min_mana, (100 / (2 + ch->level - level)));
00297 }
00298 
00299 
00300 
00301 /*
00302  * The kludgy global is for spells who want more stuff from command line.
00303  */
00304 char *target_name;
00305 
00306 void do_cast (CHAR_DATA * ch, char *argument)
00307 {
00308     char arg1[MAX_INPUT_LENGTH];
00309     char arg2[MAX_INPUT_LENGTH];
00310     CHAR_DATA *victim;
00311     OBJ_DATA *obj;
00312     void *vo;
00313     int mana;
00314     int sn;
00315     int target;
00316 
00317     /*
00318      * Switched NPC's can cast spells, but others can't.
00319      */
00320     if (IS_NPC (ch) && ch->desc == NULL)
00321         return;
00322 
00323     target_name = one_argument (argument, arg1);
00324     one_argument (target_name, arg2);
00325 
00326     if (arg1[0] == '\0')
00327     {
00328         send_to_char ("Cast which what where?\n\r", ch);
00329         return;
00330     }
00331 
00332     if ((sn = find_spell (ch, arg1)) < 1
00333         || skill_table[sn].spell_fun == spell_null || (!IS_NPC (ch)
00334                                                        && (ch->level <
00335                                                            skill_table
00336                                                            [sn].skill_level
00337                                                            [ch->class]
00338                                                            || ch->
00339                                                            pcdata->learned[sn]
00340                                                            == 0)))
00341     {
00342         send_to_char ("You don't know any spells of that name.\n\r", ch);
00343         return;
00344     }
00345 
00346     if (ch->position < skill_table[sn].minimum_position)
00347     {
00348         send_to_char ("You can't concentrate enough.\n\r", ch);
00349         return;
00350     }
00351 
00352     if (ch->level + 2 == skill_table[sn].skill_level[ch->class])
00353         mana = 50;
00354     else
00355         mana = UMAX (skill_table[sn].min_mana,
00356                      100 / (2 + ch->level -
00357                             skill_table[sn].skill_level[ch->class]));
00358 
00359     /*
00360      * Locate targets.
00361      */
00362     victim = NULL;
00363     obj = NULL;
00364     vo = NULL;
00365     target = TARGET_NONE;
00366 
00367     switch (skill_table[sn].target)
00368     {
00369         default:
00370             bug ("Do_cast: bad target for sn %d.", sn);
00371             return;
00372 
00373         case TAR_IGNORE:
00374             break;
00375 
00376         case TAR_CHAR_OFFENSIVE:
00377             if (arg2[0] == '\0')
00378             {
00379                 if ((victim = ch->fighting) == NULL)
00380                 {
00381                     send_to_char ("Cast the spell on whom?\n\r", ch);
00382                     return;
00383                 }
00384             }
00385             else
00386             {
00387           /*     if (!str_cmp(target_name, "all") && ch->level > 52)
00388         {
00389             char at_buf[MAX_STRING_LENGTH];
00390             
00391             for (d = descriptor_list; d != NULL; d = d->next)
00392             {
00393                 if (IS_NPC(d->character))
00394                     continue;
00395                 free_string(at_buf);
00396                 strcat(at_buf, d->character->name);
00397                 strcat(at_buf, " ");
00398                 strcat(at_buf, "c ");
00399                 strcat(at_buf, arg1);
00400                 strcat(at_buf, d->character->name);
00401                 do_function(ch, &do_at,at_buf );
00402                 
00403             }
00404         }*/
00405         if ((victim = get_char_room (ch, target_name)) == NULL)
00406                 {
00407                     send_to_char ("They aren't here.\n\r", ch);
00408                     return;
00409                 }
00410             }
00411 /*
00412         if ( ch == victim )
00413         {
00414             send_to_char( "You can't do that to yourself.\n\r", ch );
00415             return;
00416         }
00417 */
00418 
00419         extern bool global_peace;
00420         if (global_peace)
00421         {
00422             send_to_char("The gods of peace have spoken. There will be no fighting.\n\r",ch);
00423             return;
00424         }
00425 
00426             if (!IS_NPC (ch))
00427             {
00428 
00429                 if (is_safe (ch, victim) && victim != ch)
00430                 {
00431                     send_to_char ("Not on that target.\n\r", ch);
00432                     return;
00433                 }
00434                 check_killer (ch, victim);
00435             }
00436 /*
00437             if (!IS_NPC(victim) && ch->clan == 0 && victim != ch)
00438         {
00439             send_to_char("Join a clan if you wish to attack players.\n\r",ch);
00440             return;
00441         }
00442         if (!IS_NPC(victim) && victim->clan == 0 && victim != ch)
00443         {
00444             send_to_char("They are not in a clan.\n\r",ch);
00445             return;
00446         }
00447 */
00448         if (IS_AFFECTED (ch, AFF_CHARM) && ch->master == victim)
00449             {
00450                 send_to_char ("You can't do that on your own follower.\n\r",
00451                               ch);
00452                 return;
00453             }
00454 
00455             vo = (void *) victim;
00456             target = TARGET_CHAR;
00457             break;
00458 
00459         case TAR_CHAR_DEFENSIVE:
00460             if (arg2[0] == '\0')
00461             {
00462                 victim = ch;
00463             }
00464             else
00465             {
00466                 if ((victim = get_char_room (ch, target_name)) == NULL)
00467                 {
00468                     send_to_char ("They aren't here.\n\r", ch);
00469                     return;
00470                 }
00471             }
00472 
00473             vo = (void *) victim;
00474             target = TARGET_CHAR;
00475             break;
00476 
00477         case TAR_CHAR_SELF:
00478             if (arg2[0] != '\0' && !is_name (target_name, ch->name))
00479             {
00480                 send_to_char ("You cannot cast this spell on another.\n\r",
00481                               ch);
00482                 return;
00483             }
00484 
00485             vo = (void *) ch;
00486             target = TARGET_CHAR;
00487             break;
00488 
00489         case TAR_OBJ_INV:
00490             if (arg2[0] == '\0')
00491             {
00492                 send_to_char ("What should the spell be cast upon?\n\r", ch);
00493                 return;
00494             }
00495 
00496             if ((obj = get_obj_carry (ch, target_name, ch)) == NULL)
00497             {
00498                 send_to_char ("You are not carrying that.\n\r", ch);
00499                 return;
00500             }
00501 
00502             vo = (void *) obj;
00503             target = TARGET_OBJ;
00504             break;
00505 
00506         case TAR_OBJ_CHAR_OFF:
00507             if (arg2[0] == '\0')
00508             {
00509                 if ((victim = ch->fighting) == NULL)
00510                 {
00511                     send_to_char ("Cast the spell on whom or what?\n\r", ch);
00512                     return;
00513                 }
00514 
00515                 target = TARGET_CHAR;
00516             }
00517             else if ((victim = get_char_room (ch, target_name)) != NULL)
00518             {
00519                 target = TARGET_CHAR;
00520             }
00521 
00522             if (target == TARGET_CHAR)
00523             {                    /* check the sanity of the attack */
00524                 if ((is_safe_spell (ch, victim, FALSE) && victim != ch))
00525                 {
00526                     send_to_char ("Not on that target.\n\r", ch);
00527                     return;
00528                 }
00529         /*if (!IS_NPC(victim) && ch->clan == 0 &&!IS_NPC(ch) && victim != ch)
00530         {
00531             send_to_char("Join a clan if you wish to attack players.\n\r",ch);
00532             return;
00533         }
00534         if (!IS_NPC(victim) && !IS_NPC(ch) && victim->clan == 0 && victim != ch)
00535         {
00536             send_to_char("They are not in a clan.\n\r",ch);
00537             return;
00538         }*/
00539 
00540 
00541                 if (IS_AFFECTED (ch, AFF_CHARM) && ch->master == victim)
00542                 {
00543                     send_to_char
00544                         ("You can't do that on your own follower.\n\r", ch);
00545                     return;
00546                 }
00547 
00548                 if (!IS_NPC (ch))
00549                     check_killer (ch, victim);
00550 
00551                 vo = (void *) victim;
00552             }
00553             else if ((obj = get_obj_here (ch, target_name)) != NULL)
00554             {
00555                 vo = (void *) obj;
00556                 target = TARGET_OBJ;
00557             }
00558             else
00559             {
00560                 send_to_char ("You don't see that here.\n\r", ch);
00561                 return;
00562             }
00563             break;
00564 
00565         case TAR_OBJ_CHAR_DEF:
00566             if (arg2[0] == '\0')
00567             {
00568                 vo = (void *) ch;
00569                 target = TARGET_CHAR;
00570             }
00571             else if ((victim = get_char_room (ch, target_name)) != NULL)
00572             {
00573                 vo = (void *) victim;
00574                 target = TARGET_CHAR;
00575             }
00576             else if ((obj = get_obj_carry (ch, target_name, ch)) != NULL)
00577             {
00578                 vo = (void *) obj;
00579                 target = TARGET_OBJ;
00580             }
00581             else
00582             {
00583                 send_to_char ("You don't see that here.\n\r", ch);
00584                 return;
00585             }
00586             break;
00587     }
00588 
00589     if (!IS_NPC (ch) && ch->mana < mana)
00590     {
00591         send_to_char ("You don't have enough mana.\n\r", ch);
00592         return;
00593     }
00594 
00595     if (str_cmp (skill_table[sn].name, "ventriloquate"))
00596         say_spell (ch, sn);
00597 
00598    if (ch->level > 51)
00599    {
00600    }
00601    else
00602    {
00603        WAIT_STATE (ch, skill_table[sn].beats);
00604    }
00605    
00606 
00607     if (number_percent () > get_skill (ch, sn))
00608     {
00609         send_to_char ("You lost your concentration.\n\r", ch);
00610         check_improve (ch, sn, FALSE, 1);
00611         if (ch->level > 51)
00612     {
00613     }
00614     else{
00615         
00616     ch->mana -= mana / 2;
00617     }
00618     }
00619     else
00620     {
00621         if (ch->level > 51) {}else {ch->mana -= mana;}
00622         if (IS_NPC (ch) || class_table[ch->class].fMana)
00623             /* class has spells */
00624             (*skill_table[sn].spell_fun) (sn, ch->level, ch, vo, target);
00625         else
00626             (*skill_table[sn].spell_fun) (sn, 3 * ch->level / 4, ch, vo, target);
00627         check_improve (ch, sn, TRUE, 1);
00628     }
00629 
00630     if ((skill_table[sn].target == TAR_CHAR_OFFENSIVE
00631          || (skill_table[sn].target == TAR_OBJ_CHAR_OFF
00632              && target == TARGET_CHAR)) && victim != ch
00633         && victim->master != ch)
00634     {
00635         CHAR_DATA *vch;
00636         CHAR_DATA *vch_next;
00637 
00638         for (vch = ch->in_room->people; vch; vch = vch_next)
00639         {
00640             vch_next = vch->next_in_room;
00641             if (victim == vch && victim->fighting == NULL)
00642             {
00643                 check_killer (victim, ch);
00644                 multi_hit (victim, ch, TYPE_UNDEFINED);
00645                 break;
00646             }
00647         }
00648     }
00649 
00650     return;
00651 }
00652 
00653 
00654 
00655 /*
00656  * Cast spells at targets using a magical object.
00657  */
00658 void obj_cast_spell (int sn, int level, CHAR_DATA * ch, CHAR_DATA * victim,
00659                      OBJ_DATA * obj)
00660 {
00661     void *vo;
00662     extern bool global_peace;
00663     int target = TARGET_NONE;
00664 
00665     if (sn <= 0)
00666         return;
00667 
00668     if (sn >= MAX_SKILL || skill_table[sn].spell_fun == 0)
00669     {
00670         bug ("Obj_cast_spell: bad sn %d.", sn);
00671         return;
00672     }
00673 
00674     switch (skill_table[sn].target)
00675     {
00676         default:
00677             bug ("Obj_cast_spell: bad target for sn %d.", sn);
00678             return;
00679 
00680         case TAR_IGNORE:
00681             vo = NULL;
00682             break;
00683 
00684         case TAR_CHAR_OFFENSIVE:
00685             if (victim == NULL)
00686                 victim = ch->fighting;
00687             if (victim == NULL)
00688             {
00689                 send_to_char ("You can't do that.\n\r", ch);
00690                 return;
00691             }
00692             if (global_peace)
00693         {
00694             send_to_char("The gods of peace have spoken. There will be no fighting\n\r",ch);
00695             return;
00696         }
00697         
00698         if (is_safe (ch, victim) && ch != victim)
00699             {
00700                 send_to_char ("Something isn't right...\n\r", ch);
00701                 return;
00702             }
00703             vo = (void *) victim;
00704             target = TARGET_CHAR;
00705             break;
00706 
00707         case TAR_CHAR_DEFENSIVE:
00708         case TAR_CHAR_SELF:
00709             if (victim == NULL)
00710                 victim = ch;
00711             vo = (void *) victim;
00712             target = TARGET_CHAR;
00713             break;
00714 
00715         case TAR_OBJ_INV:
00716             if (obj == NULL)
00717             {
00718                 send_to_char ("You can't do that.\n\r", ch);
00719                 return;
00720             }
00721             vo = (void *) obj;
00722             target = TARGET_OBJ;
00723             break;
00724 
00725         case TAR_OBJ_CHAR_OFF:
00726             if (victim == NULL && obj == NULL)
00727             {
00728                 if (ch->fighting != NULL)
00729                     victim = ch->fighting;
00730                 else
00731                 {
00732                     send_to_char ("You can't do that.\n\r", ch);
00733                     return;
00734                 }
00735             }
00736 
00737             if (victim != NULL)
00738             {
00739                 if (is_safe_spell (ch, victim, FALSE) && ch != victim)
00740                 {
00741                     send_to_char ("Somehting isn't right...\n\r", ch);
00742                     return;
00743                 }
00744 
00745                 vo = (void *) victim;
00746                 target = TARGET_CHAR;
00747             }
00748             else
00749             {
00750                 vo = (void *) obj;
00751                 target = TARGET_OBJ;
00752             }
00753             break;
00754 
00755 
00756         case TAR_OBJ_CHAR_DEF:
00757             if (victim == NULL && obj == NULL)
00758             {
00759                 vo = (void *) ch;
00760                 target = TARGET_CHAR;
00761             }
00762             else if (victim != NULL)
00763             {
00764                 vo = (void *) victim;
00765                 target = TARGET_CHAR;
00766             }
00767             else
00768             {
00769                 vo = (void *) obj;
00770                 target = TARGET_OBJ;
00771             }
00772 
00773             break;
00774     }
00775 
00776     target_name = "";
00777     (*skill_table[sn].spell_fun) (sn, level, ch, vo, target);
00778 
00779 
00780 
00781     if ((skill_table[sn].target == TAR_CHAR_OFFENSIVE
00782          || (skill_table[sn].target == TAR_OBJ_CHAR_OFF
00783              && target == TARGET_CHAR)) && victim != ch
00784         && victim->master != ch)
00785     {
00786         CHAR_DATA *vch;
00787         CHAR_DATA *vch_next;
00788 
00789         for (vch = ch->in_room->people; vch; vch = vch_next)
00790         {
00791             vch_next = vch->next_in_room;
00792             if (victim == vch && victim->fighting == NULL)
00793             {
00794                 check_killer (victim, ch);
00795                 multi_hit (victim, ch, TYPE_UNDEFINED);
00796                 break;
00797             }
00798         }
00799     }
00800 
00801     return;
00802 }
00803 
00804 
00805 
00806 /*
00807  * Spell functions.
00808  */
00809 void spell_tribul_kill (int sn, int level, CHAR_DATA *ch, void *vo, int target)
00810 {
00811     CHAR_DATA *victim = (CHAR_DATA*) vo;
00812     int dam;
00813     int i;
00814     for (i=0;i <10;i++)
00815     {
00816     dam = dice(level, 500);
00817 if (saves_spell(level, victim, DAM_ACID))
00818         dam /=2;
00819     damage (ch,victim,dam,sn,DAM_ACID, TRUE);
00820     }
00821     return;
00822 }
00823 
00824 void spell_acid_blast (int sn, int level, CHAR_DATA * ch, void *vo,
00825                        int target)
00826 {
00827     CHAR_DATA *victim = (CHAR_DATA *) vo;
00828     int dam;
00829 
00830     dam = dice (level, 12);
00831     if (saves_spell (level, victim, DAM_ACID))
00832         dam /= 2;
00833     damage (ch, victim, dam, sn, DAM_ACID, TRUE);
00834     return;
00835 }
00836 
00837 
00838 
00839 void spell_armor (int sn, int level, CHAR_DATA * ch, void *vo, int target)
00840 {
00841     CHAR_DATA *victim = (CHAR_DATA *) vo;
00842     AFFECT_DATA af;
00843 
00844     if (is_affected (victim, sn))
00845     {
00846         if (victim == ch)
00847             send_to_char ("You are already armored.\n\r", ch);
00848         else
00849             act ("$N is already armored.", ch, NULL, victim, TO_CHAR);
00850         return;
00851     }
00852     af.where = TO_AFFECTS;
00853     af.type = sn;
00854     af.level = level;
00855     af.duration = 24;
00856     af.modifier = -20;
00857     af.location = APPLY_AC;
00858     af.bitvector = 0;
00859     affect_to_char (victim, &af);
00860     send_to_char ("You feel someone protecting you.\n\r", victim);
00861     if (ch != victim)
00862         act ("$N is protected by your magic.", ch, NULL, victim, TO_CHAR);
00863     return;
00864 }
00865 
00866 
00867 
00868 void spell_bless (int sn, int level, CHAR_DATA * ch, void *vo, int target)
00869 {
00870     CHAR_DATA *victim;
00871     OBJ_DATA *obj;
00872     AFFECT_DATA af;
00873 
00874     /* deal with the object case first */
00875     if (target == TARGET_OBJ)
00876     {
00877         obj = (OBJ_DATA *) vo;
00878         if (IS_OBJ_STAT (obj, ITEM_BLESS))
00879         {
00880             act ("$p is already blessed.", ch, obj, NULL, TO_CHAR);
00881             return;
00882         }
00883 
00884         if (IS_OBJ_STAT (obj, ITEM_EVIL))
00885         {
00886             AFFECT_DATA *paf;
00887 
00888             paf = affect_find (obj->affected, gsn_curse);
00889             if (!saves_dispel
00890                 (level, paf != NULL ? paf->level : obj->level, 0))
00891             {
00892                 if (paf != NULL)
00893                     affect_remove_obj (obj, paf);
00894                 act ("$p glows a pale blue.", ch, obj, NULL, TO_ALL);
00895                 REMOVE_BIT (obj->extra_flags, ITEM_EVIL);
00896                 return;
00897             }
00898             else
00899             {
00900                 act ("The evil of $p is too powerful for you to overcome.",
00901                      ch, obj, NULL, TO_CHAR);
00902                 return;
00903             }
00904         }
00905 
00906         af.where = TO_OBJECT;
00907         af.type = sn;
00908         af.level = level;
00909         af.duration = 6 + level;
00910         af.location = APPLY_SAVES;
00911         af.modifier = -1;
00912         af.bitvector = ITEM_BLESS;
00913         affect_to_obj (obj, &af);
00914 
00915         act ("$p glows with a holy aura.", ch, obj, NULL, TO_ALL);
00916 
00917         if (obj->wear_loc != WEAR_NONE)
00918             ch->saving_throw -= 1;
00919         return;
00920     }
00921 
00922     /* character target */
00923     victim = (CHAR_DATA *) vo;
00924 
00925 
00926     if (victim->position == POS_FIGHTING || is_affected (victim, sn))
00927     {
00928         if (victim == ch)
00929             send_to_char ("You are already blessed.\n\r", ch);
00930         else
00931             act ("$N already has divine favor.", ch, NULL, victim, TO_CHAR);
00932         return;
00933     }
00934 
00935     af.where = TO_AFFECTS;
00936     af.type = sn;
00937     af.level = level;
00938     af.duration = 6 + level;
00939     af.location = APPLY_HITROLL;
00940     af.modifier = level / 8;
00941     af.bitvector = 0;
00942     affect_to_char (victim, &af);
00943 
00944     af.location = APPLY_SAVING_SPELL;
00945     af.modifier = 0 - level / 8;
00946     affect_to_char (victim, &af);
00947     send_to_char ("You feel righteous.\n\r", victim);
00948     if (ch != victim)
00949         act ("You grant $N the favor of your god.", ch, NULL, victim,
00950              TO_CHAR);
00951     return;
00952 }
00953 
00954 
00955 
00956 void spell_blindness (int sn, int level, CHAR_DATA * ch, void *vo, int target)
00957 {
00958     CHAR_DATA *victim = (CHAR_DATA *) vo;
00959     AFFECT_DATA af;
00960 
00961     if (IS_AFFECTED (victim, AFF_BLIND))
00962     {
00963         send_to_char("They are already blind!\n\r",ch);
00964         return;
00965     }
00966     if (saves_spell (level, victim, DAM_OTHER))
00967     {
00968         send_to_char("You failed.\n\r",ch);
00969         return;
00970     }
00971     
00972 
00973 
00974     af.where = TO_AFFECTS;
00975     af.type = sn;
00976     af.level = level;
00977     af.location = APPLY_HITROLL;
00978     af.modifier = -4;
00979     af.duration = 1 + level;
00980     af.bitvector = AFF_BLIND;
00981     affect_to_char (victim, &af);
00982     send_to_char ("You are blinded!\n\r", victim);
00983     act ("$n appears to be blinded.", victim, NULL, NULL, TO_ROOM);
00984     act ("$n appaers to be blinded.", victim, NULL, NULL, TO_CHAR);
00985     return;
00986 }
00987 
00988 
00989 
00990 void spell_burning_hands (int sn, int level, CHAR_DATA * ch, void *vo,
00991                           int target)
00992 {
00993     CHAR_DATA *victim = (CHAR_DATA *) vo;
00994     static const sh_int dam_each[] = {
00995         0,
00996         0, 0, 0, 0, 14, 17, 20, 23, 26, 29,
00997         29, 29, 30, 30, 31, 31, 32, 32, 33, 33,
00998         34, 34, 35, 35, 36, 36, 37, 37, 38, 38,
00999         39, 39, 40, 40, 41, 41, 42, 42, 43, 43,
01000         44, 44, 45, 45, 46, 46, 47, 47, 48, 48
01001     };
01002     int dam;
01003 
01004     level = UMIN (level, sizeof (dam_each) / sizeof (dam_each[0]) - 1);
01005     level = UMAX (0, level);
01006     dam = number_range (dam_each[level] / 2, dam_each[level] * 2);
01007     if (saves_spell (level, victim, DAM_FIRE))
01008         dam /= 2;
01009     damage (ch, victim, dam, sn, DAM_FIRE, TRUE);
01010     return;
01011 }
01012 
01013 
01014 
01015 void spell_call_lightning (int sn, int level, CHAR_DATA * ch, void *vo,
01016                            int target)
01017 {
01018     CHAR_DATA *vch;
01019     CHAR_DATA *vch_next;
01020     int dam;
01021 
01022     if (!IS_OUTSIDE (ch))
01023     {
01024         send_to_char ("You must be out of doors.\n\r", ch);
01025         return;
01026     }
01027 
01028     if (weather_info.sky < SKY_RAINING)
01029     {
01030         send_to_char ("You need bad weather.\n\r", ch);
01031         return;
01032     }
01033 
01034     dam = dice (level / 2, 8);
01035 
01036     send_to_char ("The Gods of lightning strikes your foes!\n\r", ch);
01037     act ("$n calls The Gods of lightning to strike $s foes!",
01038          ch, NULL, NULL, TO_ROOM);
01039 
01040     for (vch = char_list; vch != NULL; vch = vch_next)
01041     {
01042         vch_next = vch->next;
01043         if (vch->in_room == NULL)
01044             continue;
01045         if (vch->in_room == ch->in_room)
01046         {
01047             if (vch != ch && (IS_NPC (ch) ? !IS_NPC (vch) : IS_NPC (vch)))
01048                 damage (ch, vch, saves_spell (level, vch, DAM_LIGHTNING)
01049                         ? dam / 2 : dam, sn, DAM_LIGHTNING, TRUE);
01050             continue;
01051         }
01052 
01053         if (vch->in_room->area == ch->in_room->area && IS_OUTSIDE (vch)
01054             && IS_AWAKE (vch))
01055             send_to_char ("Lightning flashes in the sky.\n\r", vch);
01056     }
01057 
01058     return;
01059 }
01060 
01061 /* RT calm spell stops all fighting in the room */
01062 
01063 void spell_calm (int sn, int level, CHAR_DATA * ch, void *vo, int target)
01064 {
01065     CHAR_DATA *vch;
01066     int mlevel = 0;
01067     int count = 0;
01068     int high_level = 0;
01069     int chance;
01070     AFFECT_DATA af;
01071 
01072     /* get sum of all mobile levels in the room */
01073     for (vch = ch->in_room->people; vch != NULL; vch = vch->next_in_room)
01074     {
01075         if (vch->position == POS_FIGHTING)
01076         {
01077             count++;
01078             if (IS_NPC (vch))
01079                 mlevel += vch->level;
01080             else
01081                 mlevel += vch->level / 2;
01082             high_level = UMAX (high_level, vch->level);
01083         }
01084     }
01085 
01086     /* compute chance of stopping combat */
01087     chance = 4 * level - high_level + 2 * count;
01088 
01089     if (IS_IMMORTAL (ch))        /* always works */
01090         mlevel = 0;
01091 
01092     if (number_range (0, chance) >= mlevel)
01093     {                            /* hard to stop large fights */
01094         for (vch = ch->in_room->people; vch != NULL; vch = vch->next_in_room)
01095         {
01096             if (IS_NPC (vch) && (IS_SET (vch->imm_flags, IMM_MAGIC) ||
01097                                  IS_SET (vch->act, ACT_UNDEAD)))
01098                 return;
01099 
01100             if (IS_AFFECTED (vch, AFF_CALM) || IS_AFFECTED (vch, AFF_BERSERK)
01101                 || is_affected (vch, skill_lookup ("frenzy")))
01102                 return;
01103 
01104             send_to_char ("A wave of calm passes over you.\n\r", vch);
01105 
01106             if (vch->fighting || vch->position == POS_FIGHTING)
01107                 stop_fighting (vch, FALSE);
01108 
01109 
01110             af.where = TO_AFFECTS;
01111             af.type = sn;
01112             af.level = level;
01113             af.duration = level / 4;
01114             af.location = APPLY_HITROLL;
01115             if (!IS_NPC (vch))
01116                 af.modifier = -5;
01117             else
01118                 af.modifier = -2;
01119             af.bitvector = AFF_CALM;
01120             affect_to_char (vch, &af);
01121 
01122             af.location = APPLY_DAMROLL;
01123             affect_to_char (vch, &af);
01124         }
01125     }
01126 }
01127 
01128 void spell_cancellation (int sn, int level, CHAR_DATA * ch, void *vo,
01129                          int target)
01130 {
01131     CHAR_DATA *victim = (CHAR_DATA *) vo;
01132     bool found = FALSE;
01133 
01134     level += 2;
01135 
01136     if ((!IS_NPC (ch) && IS_NPC (victim) &&
01137          !(IS_AFFECTED (ch, AFF_CHARM) && ch->master == victim)) ||
01138         (IS_NPC (ch) && !IS_NPC (victim)))
01139     {
01140         send_to_char ("You failed, try dispel magic.\n\r", ch);
01141         return;
01142     }
01143 
01144     /* unlike dispel magic, the victim gets NO save */
01145 
01146     /* begin running through the spells */
01147 
01148     if (check_dispel (level, victim, skill_lookup ("armor")))
01149         found = TRUE;
01150 
01151     if (check_dispel (level, victim, skill_lookup ("bless")))
01152         found = TRUE;
01153 
01154     if (check_dispel (level, victim, skill_lookup ("blindness")))
01155     {
01156         found = TRUE;
01157         act ("$n is no longer blinded.", victim, NULL, NULL, TO_ROOM);
01158     }
01159 
01160     if (check_dispel (level, victim, skill_lookup ("calm")))
01161     {
01162         found = TRUE;
01163         act ("$n no longer looks so peaceful...", victim, NULL, NULL,
01164              TO_ROOM);
01165     }
01166 
01167     if (check_dispel (level, victim, skill_lookup ("change sex")))
01168     {
01169         found = TRUE;
01170         act ("$n looks more like $mself again.", victim, NULL, NULL, TO_ROOM);
01171     }
01172 
01173     if (check_dispel (level, victim, skill_lookup ("charm person")))
01174     {
01175         found = TRUE;
01176         act ("$n regains $s free will.", victim, NULL, NULL, TO_ROOM);
01177     }
01178 
01179     if (check_dispel (level, victim, skill_lookup ("chill touch")))
01180     {
01181         found = TRUE;
01182         act ("$n looks warmer.", victim, NULL, NULL, TO_ROOM);
01183     }
01184 
01185     if (check_dispel (level, victim, skill_lookup ("curse")))
01186         found = TRUE;
01187 
01188     if (check_dispel (level, victim, skill_lookup ("detect evil")))
01189         found = TRUE;
01190 
01191     if (check_dispel (level, victim, skill_lookup ("detect good")))
01192         found = TRUE;
01193 
01194     if (check_dispel (level, victim, skill_lookup ("detect hidden")))
01195         found = TRUE;
01196 
01197     if (check_dispel (level, victim, skill_lookup ("detect invis")))
01198         found = TRUE;
01199 
01200     if (check_dispel (level, victim, skill_lookup ("detect magic")))
01201         found = TRUE;
01202 
01203     if (check_dispel (level, victim, skill_lookup ("faerie fire")))
01204     {
01205         act ("$n's outline fades.", victim, NULL, NULL, TO_ROOM);
01206         found = TRUE;
01207     }
01208 
01209     if (check_dispel (level, victim, skill_lookup ("fly")))
01210     {
01211         act ("$n falls to the ground!", victim, NULL, NULL, TO_ROOM);
01212     victim->position = POS_STANDING;
01213         found = TRUE;
01214     }
01215 
01216     if (check_dispel (level, victim, skill_lookup ("frenzy")))
01217     {
01218         act ("$n no longer looks so wild.", victim, NULL, NULL, TO_ROOM);;
01219         found = TRUE;
01220     }
01221 
01222     if (check_dispel (level, victim, skill_lookup ("giant strength")))
01223     {
01224         act ("$n no longer looks so mighty.", victim, NULL, NULL, TO_ROOM);
01225         found = TRUE;
01226     }
01227 
01228     if (check_dispel (level, victim, skill_lookup ("haste")))
01229     {
01230         act ("$n is no longer moving so quickly.", victim, NULL, NULL,
01231              TO_ROOM);
01232         found = TRUE;
01233     }
01234 
01235     if (check_dispel (level, victim, skill_lookup ("infravision")))
01236         found = TRUE;
01237 
01238     if (check_dispel (level, victim, skill_lookup ("invis")))
01239     {
01240         act ("$n fades into existance.", victim, NULL, NULL, TO_ROOM);
01241         found = TRUE;
01242     }
01243 
01244     if (check_dispel (level, victim, skill_lookup ("mass invis")))
01245     {
01246         act ("$n fades into existance.", victim, NULL, NULL, TO_ROOM);
01247         found = TRUE;
01248     }
01249 
01250     if (check_dispel (level, victim, skill_lookup ("pass door")))
01251         found = TRUE;
01252 
01253     if (check_dispel (level, victim, skill_lookup ("protection evil")))
01254         found = TRUE;
01255 
01256     if (check_dispel (level, victim, skill_lookup ("protection good")))
01257         found = TRUE;
01258 
01259     if (check_dispel (level, victim, skill_lookup ("sanctuary")))
01260     {
01261         act ("The white aura around $n's body vanishes.",
01262              victim, NULL, NULL, TO_ROOM);
01263         found = TRUE;
01264     }
01265 
01266     if (check_dispel (level, victim, skill_lookup ("shield")))
01267     {
01268         act ("The shield protecting $n vanishes.", victim, NULL, NULL,
01269              TO_ROOM);
01270         found = TRUE;
01271     }
01272 
01273     if (check_dispel (level, victim, skill_lookup ("sleep")))
01274         found = TRUE;
01275 
01276     if (check_dispel (level, victim, skill_lookup ("slow")))
01277     {
01278         act ("$n is no longer moving so slowly.", victim, NULL, NULL,
01279              TO_ROOM);
01280         found = TRUE;
01281     }
01282 
01283     if (check_dispel (level, victim, skill_lookup ("stone skin")))
01284     {
01285         act ("$n's skin regains its normal texture.", victim, NULL, NULL,
01286              TO_ROOM);
01287         found = TRUE;
01288     }
01289 
01290     if (check_dispel (level, victim, skill_lookup ("weaken")))
01291     {
01292         act ("$n looks stronger.", victim, NULL, NULL, TO_ROOM);
01293         found = TRUE;
01294     }
01295 
01296     if (found)
01297         send_to_char ("Ok.\n\r", ch);
01298     else
01299         send_to_char ("Ok.\n\r", ch);
01300 }
01301 
01302 void spell_cause_light (int sn, int level, CHAR_DATA * ch, void *vo,
01303                         int target)
01304 {
01305     damage (ch, (CHAR_DATA *) vo, dice (1, 8) + level / 3, sn, DAM_HARM,
01306             TRUE);
01307     return;
01308 }
01309 
01310 
01311 
01312 void spell_cause_critical (int sn, int level, CHAR_DATA * ch, void *vo,
01313                            int target)
01314 {
01315     damage (ch, (CHAR_DATA *) vo, dice (3, 8) + level - 6, sn, DAM_HARM,
01316             TRUE);
01317     return;
01318 }
01319 
01320 
01321 
01322 void spell_cause_serious (int sn, int level, CHAR_DATA * ch, void *vo,
01323                           int target)
01324 {
01325     damage (ch, (CHAR_DATA *) vo, dice (2, 8) + level / 2, sn, DAM_HARM,
01326             TRUE);
01327     return;
01328 }
01329 
01330 void spell_chain_lightning (int sn, int level, CHAR_DATA * ch, void *vo,
01331                             int target)
01332 {
01333     CHAR_DATA *victim = (CHAR_DATA *) vo;
01334     CHAR_DATA *tmp_vict, *last_vict, *next_vict;
01335     bool found;
01336     int dam;
01337 
01338     /* first strike */
01339 
01340     act ("A lightning bolt leaps from $n's hand and arcs to $N.",
01341          ch, NULL, victim, TO_ROOM);
01342     act ("A lightning bolt leaps from your hand and arcs to $N.",
01343          ch, NULL, victim, TO_CHAR);
01344     act ("A lightning bolt leaps from $n's hand and hits you!",
01345          ch, NULL, victim, TO_VICT);
01346 
01347     dam = dice (level, 6);
01348     if (saves_spell (level, victim, DAM_LIGHTNING))
01349         dam /= 3;
01350     damage (ch, victim, dam, sn, DAM_LIGHTNING, TRUE);
01351     last_vict = victim;
01352     level -= 4;                    /* decrement damage */
01353 
01354     /* new targets */
01355     while (level > 0)
01356     {
01357         found = FALSE;
01358         for (tmp_vict = ch->in_room->people;
01359              tmp_vict != NULL; tmp_vict = next_vict)
01360         {
01361             next_vict = tmp_vict->next_in_room;
01362             if (!is_safe_spell (ch, tmp_vict, TRUE) && tmp_vict != last_vict)
01363             {
01364                 found = TRUE;
01365                 last_vict = tmp_vict;
01366                 act ("The bolt arcs to $n!", tmp_vict, NULL, NULL, TO_ROOM);
01367                 act ("The bolt hits you!", tmp_vict, NULL, NULL, TO_CHAR);
01368                 dam = dice (level, 6);
01369                 if (saves_spell (level, tmp_vict, DAM_LIGHTNING))
01370                     dam /= 3;
01371                 damage (ch, tmp_vict, dam, sn, DAM_LIGHTNING, TRUE);
01372                 level -= 4;        /* decrement damage */
01373             }
01374         }                        /* end target searching loop */
01375 
01376         if (!found)
01377         {                        /* no target found, hit the caster */
01378             if (ch == NULL)
01379                 return;
01380 
01381             if (last_vict == ch)
01382             {                    /* no double hits */
01383                 act ("The bolt seems to have fizzled out.", ch, NULL, NULL,
01384                      TO_ROOM);
01385                 act ("The bolt grounds out through your body.", ch, NULL,
01386                      NULL, TO_CHAR);
01387                 return;
01388             }
01389 
01390             last_vict = ch;
01391             act ("The bolt arcs to $n...whoops!", ch, NULL, NULL, TO_ROOM);
01392             send_to_char ("You are struck by your own lightning!\n\r", ch);
01393             dam = dice (level, 6);
01394             if (saves_spell (level, ch, DAM_LIGHTNING))
01395                 dam /= 3;
01396             damage (ch, ch, dam, sn, DAM_LIGHTNING, TRUE);
01397             level -= 4;            /* decrement damage */
01398             if (ch == NULL)
01399                 return;
01400         }
01401         /* now go back and find more targets */
01402     }
01403 }
01404 
01405 
01406 void spell_change_sex (int sn, int level, CHAR_DATA * ch, void *vo,
01407                        int target)
01408 {
01409     CHAR_DATA *victim = (CHAR_DATA *) vo;
01410     AFFECT_DATA af;
01411 
01412     if (is_affected (victim, sn))
01413     {
01414         if (victim == ch)
01415             send_to_char ("You've already been changed.\n\r", ch);
01416         else
01417             act ("$N has already had $s(?) sex changed.", ch, NULL, victim,
01418                  TO_CHAR);
01419         return;
01420     }
01421     if (saves_spell (level, victim, DAM_OTHER))
01422         return;
01423     af.where = TO_AFFECTS;
01424     af.type = sn;
01425     af.level = level;
01426     af.duration = 2 * level;
01427     af.location = APPLY_SEX;
01428     do
01429     {
01430         af.modifier = number_range (0, 2) - victim->sex;
01431     }
01432     while (af.modifier == 0);
01433     af.bitvector = 0;
01434     affect_to_char (victim, &af);
01435     send_to_char ("You feel different.\n\r", victim);
01436     act ("$n doesn't look like $mself anymore...", victim, NULL, NULL,
01437          TO_ROOM);
01438     return;
01439 }
01440 
01441 
01442 
01443 void spell_charm_person (int sn, int level, CHAR_DATA * ch, void *vo,
01444                          int target)
01445 {
01446     CHAR_DATA *victim = (CHAR_DATA *) vo;
01447     AFFECT_DATA af;
01448 
01449     if (is_safe (ch, victim))
01450         return;
01451 
01452     if (victim == ch)
01453     {
01454         send_to_char ("You like yourself even better!\n\r", ch);
01455         return;
01456     }
01457 
01458     if (IS_AFFECTED (victim, AFF_CHARM)
01459         || IS_AFFECTED (ch, AFF_CHARM)
01460         || level < victim->level || IS_SET (victim->imm_flags, IMM_CHARM)
01461         || saves_spell (level, victim, DAM_CHARM))
01462         return;
01463 
01464 
01465     if (IS_SET (victim->in_room->room_flags, ROOM_LAW))
01466     {
01467         send_to_char
01468             ("You failed.\n\r", ch);
01469         return;
01470     }
01471 
01472     if (victim->master)
01473         stop_follower (victim);
01474     add_follower (victim, ch);
01475     victim->leader = ch;
01476     af.where = TO_AFFECTS;
01477     af.type = sn;
01478     af.level = level;
01479     af.duration = number_fuzzy (level / 4);
01480     af.location = 0;
01481     af.modifier = 0;
01482     af.bitvector = AFF_CHARM;
01483     affect_to_char (victim, &af);
01484     act ("Isn't $n just so nice?", ch, NULL, victim, TO_VICT);
01485     if (ch != victim)
01486         act ("$N looks at you with adoring eyes.", ch, NULL, victim, TO_CHAR);
01487     return;
01488 }
01489 
01490 
01491 
01492 void spell_chill_touch (int sn, int level, CHAR_DATA * ch, void *vo,
01493                         int target)
01494 {
01495     CHAR_DATA *victim = (CHAR_DATA *) vo;
01496     static const sh_int dam_each[] = {
01497         0,
01498         0, 0, 6, 7, 8, 9, 12, 13, 13, 13,
01499         14, 14, 14, 15, 15, 15, 16, 16, 16, 17,
01500         17, 17, 18, 18, 18, 19, 19, 19, 20, 20,
01501         20, 21, 21, 21, 22, 22, 22, 23, 23, 23,
01502         24, 24, 24, 25, 25, 25, 26, 26, 26, 27
01503     };
01504     AFFECT_DATA af;
01505     int dam;
01506 
01507     level = UMIN (level, sizeof (dam_each) / sizeof (dam_each[0]) - 1);
01508     level = UMAX (0, level);
01509     dam = number_range (dam_each[level] / 2, dam_each[level] * 2);
01510     if (!saves_spell (level, victim, DAM_COLD))
01511     {
01512         act ("$n turns blue and shivers.", victim, NULL, NULL, TO_ROOM);
01513         af.where = TO_AFFECTS;
01514         af.type = sn;
01515         af.level = level;
01516         af.duration = 6;
01517         af.location = APPLY_STR;
01518         af.modifier = -1;
01519         af.bitvector = 0;
01520         affect_join (victim, &af);
01521     }
01522     else
01523     {
01524         dam /= 2;
01525     }
01526 
01527     damage (ch, victim, dam, sn, DAM_COLD, TRUE);
01528     return;
01529 }
01530 
01531 
01532 
01533 void spell_colour_spray (int sn, int level, CHAR_DATA * ch, void *vo,
01534                          int target)
01535 {
01536     CHAR_DATA *victim = (CHAR_DATA *) vo;
01537     static const sh_int dam_each[] = {
01538         0,
01539         0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01540         30, 35, 40, 45, 50, 55, 55, 55, 56, 57,
01541         58, 58, 59, 60, 61, 61, 62, 63, 64, 64,
01542         65, 66, 67, 67, 68, 69, 70, 70, 71, 72,
01543         73, 73, 74, 75, 76, 76, 77, 78, 79, 79
01544     };
01545     int dam;
01546 
01547     level = UMIN (level, sizeof (dam_each) / sizeof (dam_each[0]) - 1);
01548     level = UMAX (0, level);
01549     dam = number_range (dam_each[level] / 2, dam_each[level] * 2);
01550     if (saves_spell (level, victim, DAM_LIGHT))
01551         dam /= 2;
01552     else
01553         spell_blindness (skill_lookup ("blindness"),
01554                          level / 2, ch, (void *) victim, TARGET_CHAR);
01555 
01556     damage (ch, victim, dam, sn, DAM_LIGHT, TRUE);
01557     return;
01558 }
01559 
01560 
01561 
01562 void spell_continual_light (int sn, int level, CHAR_DATA * ch, void *vo,
01563                             int target)
01564 {
01565     OBJ_DATA *light;
01566     
01567     if (target_name[0] != '\0')
01568     {                            /* do a glow on some object */
01569         light = get_obj_carry (ch, target_name, ch);
01570 
01571         if (light == NULL)
01572         {
01573             send_to_char ("You don't see that here.\n\r", ch);
01574             return;
01575         }
01576 
01577         if (IS_OBJ_STAT (light, ITEM_GLOW))
01578         {
01579             act ("$p is already glowing.", ch, light, NULL, TO_CHAR);
01580             return;
01581         }
01582 
01583         SET_BIT (light->extra_flags, ITEM_GLOW);
01584         act ("$p glows with a white light.", ch, light, NULL, TO_ALL);
01585         return;
01586     }
01587 
01588     if ((light = create_object (get_obj_index (OBJ_VNUM_LIGHT_BALL), 0)) == NULL)
01589     {
01590         send_to_char("ERROR! Create_object returned NULL, please seek a coder.\n\r",ch);
01591         return;
01592     }
01593     
01594     obj_to_room (light, ch->in_room);
01595     
01596 
01597     act ("$n twiddles $s thumbs and $p appears.", ch, light, NULL, TO_ROOM);
01598     act ("You twiddle your thumbs and $p appears.", ch, light, NULL, TO_CHAR);
01599     return;
01600 }
01601 
01602 
01603 
01604 void spell_control_weather (int sn, int level, CHAR_DATA * ch, void *vo,
01605                             int target)
01606 {
01607     if (!str_cmp (target_name, "better"))
01608         weather_info.change += dice (level / 3, 4);
01609     else if (!str_cmp (target_name, "worse"))
01610         weather_info.change -= dice (level / 3, 4);
01611     else
01612         send_to_char ("Do you want it to get better or worse?\n\r", ch);
01613 
01614     send_to_char ("Ok.\n\r", ch);
01615     return;
01616 }
01617 
01618 
01619 
01620 void spell_create_food (int sn, int level, CHAR_DATA * ch, void *vo,
01621                         int target)
01622 {
01623     OBJ_DATA *mushroom;
01624 
01625     if ((mushroom = create_object (get_obj_index (OBJ_VNUM_MUSHROOM), 0)) == NULL)
01626     {
01627         send_to_char("ERROR: Object returns NULL, please find a coder.\n\r",ch);
01628         return;
01629     }
01630     mushroom->value[0]