Crossfire Server, Branch 1.12  R12190
spell_effect.c
Go to the documentation of this file.
00001 /*
00002  * static char *rcsid_spell_effect_c =
00003  *   "$Id: spell_effect.c 11578 2009-02-23 22:02:27Z lalo $";
00004  */
00005 
00006 
00007 /*
00008     CrossFire, A Multiplayer game for X-windows
00009 
00010     Copyright (C) 2002-2006 Mark Wedel & Crossfire Development Team
00011     Copyright (C) 1992 Frank Tore Johansen
00012 
00013     This program is free software; you can redistribute it and/or modify
00014     it under the terms of the GNU General Public License as published by
00015     the Free Software Foundation; either version 2 of the License, or
00016     (at your option) any later version.
00017 
00018     This program is distributed in the hope that it will be useful,
00019     but WITHOUT ANY WARRANTY; without even the implied warranty of
00020     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021     GNU General Public License for more details.
00022 
00023     You should have received a copy of the GNU General Public License
00024     along with this program; if not, write to the Free Software
00025     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00026 
00027     The authors can be reached via e-mail at crossfire-devel@real-time.com
00028 */
00029 
00036 #include <global.h>
00037 #include <object.h>
00038 #include <living.h>
00039 #ifndef __CEXTRACT__
00040 #include <sproto.h>
00041 #endif
00042 #include <spells.h>
00043 #include <sounds.h>
00044 
00055 void cast_magic_storm(object *op, object *tmp, int lvl) {
00056     if (!tmp)
00057         return; /* error */
00058     tmp->level = op->level;
00059     tmp->x = op->x;
00060     tmp->y = op->y;
00061     tmp->range += lvl/5;  /* increase the area of destruction */
00062     tmp->duration += lvl/5;
00063 
00064     /* Put a cap on duration for this - if the player fails in their
00065      * apartment, don't want it to go on so long that it kills them
00066      * multiple times.  Also, damge already increases with level,
00067      * so don't really need to increase the duration as much either.
00068      */
00069     if (tmp->duration >= 40)
00070         tmp->duration = 40;
00071     tmp->stats.dam = lvl; /* nasty recoils! */
00072     tmp->stats.maxhp = tmp->count; /* tract single parent */
00073     insert_ob_in_map(tmp, op->map, op, 0);
00074 }
00075 
00090 int recharge(object *op, object *caster, object *spell_ob) {
00091     object *wand, *tmp;
00092     int ncharges;
00093     char name[MAX_BUF];
00094 
00095     wand = find_marked_object(op);
00096     if (wand == NULL || wand->type != WAND) {
00097         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
00098                       "You need to mark the wand you want to recharge.", NULL);
00099         return 0;
00100     }
00101     if (!(random_roll(0, 3, op, PREFER_HIGH))) {
00102         query_name(wand, name, MAX_BUF);
00103         draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
00104                              "The %s vibrates violently, then explodes!",
00105                              "The %s vibrates violently, then explodes!",
00106                              name);
00107         play_sound_map(SOUND_TYPE_ITEM, wand, 0, "explode");
00108         remove_ob(wand);
00109         free_object(wand);
00110         tmp = create_archetype("fireball");
00111         tmp->stats.dam = (spell_ob->stats.dam+SP_level_dam_adjust(caster, spell_ob))/10;
00112         if (!tmp->stats.dam)
00113             tmp->stats.dam = 1;
00114         tmp->stats.hp = tmp->stats.dam/2;
00115         if (tmp->stats.hp < 2)
00116             tmp->stats.hp = 2;
00117         tmp->x = op->x;
00118         tmp->y = op->y;
00119         insert_ob_in_map(tmp, op->map, NULL, 0);
00120         return 1;
00121     }
00122 
00123     ncharges = (spell_ob->stats.dam+SP_level_dam_adjust(caster, spell_ob));
00124     if (wand->inv && wand->inv->level)
00125         ncharges /= wand->inv->level;
00126     else {
00127         query_name(wand, name, MAX_BUF);
00128         draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
00129                              "Your %s is broken.",
00130                              "Your %s is broken.",
00131                              name);
00132         return 0;
00133     }
00134     if (!ncharges)
00135         ncharges = 1;
00136 
00137     wand->stats.food += ncharges;
00138     query_name(wand, name, MAX_BUF);
00139     draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_SUCCESS,
00140                          "The %s glows with power.",
00141                          "The %s glows with power.",
00142                          name);
00143 
00144     if (wand->arch && QUERY_FLAG(&wand->arch->clone, FLAG_ANIMATE)) {
00145         SET_FLAG(wand, FLAG_ANIMATE);
00146         wand->speed = wand->arch->clone.speed;
00147         update_ob_speed(wand);
00148     }
00149     return 1;
00150 }
00151 
00152 /******************************************************************************
00153  * Start of polymorph related functions.
00154  *
00155  * Changed around for 0.94.3 - it will now look through and use all the
00156  * possible choices for objects/monsters (before it was teh first 80 -
00157  * arbitrary hardcoded limit in this file.)  Doing this will be a bit
00158  * slower however - while before, it traversed the archetypes once and
00159  * stored them into an array, it will now potentially traverse it
00160  * an average of 1.5 times.  This is probably more costly on the polymorph
00161  * item function, since it is possible a couple lookups might be needed before
00162  * an item of proper value is generated.
00163  */
00164 
00173 static void polymorph_living(object *op, int level) {
00174     archetype *at;
00175     int x = op->x, y = op->y, numat = 0, choice, friendly;
00176     mapstruct *map = op->map;
00177     object *tmp, *next, *owner;
00178 
00179     if (op->head)
00180         op = op->head;
00181 
00182     /* High level creatures are immune, as are creatures immune to magic.  Otherwise,
00183      * give the creature a saving throw.
00184      */
00185     if (op->level >= level*2
00186     || did_make_save(op, op->level, op->resist[ATNR_MAGIC]/10)
00187     || (op->resist[ATNR_MAGIC] == 100))
00188         return;
00189 
00190     remove_ob(op);
00191 
00192     /* First, count up the number of legal matches */
00193     for (at = first_archetype; at != NULL; at = at->next)
00194         if ((QUERY_FLAG((&at->clone), FLAG_MONSTER) == QUERY_FLAG(op, FLAG_MONSTER))
00195         && (find_free_spot(&at->clone, map, x, y, 0, SIZEOFFREE) != -1)) {
00196             numat++;
00197         }
00198     if (!numat) {
00199         insert_ob_in_map(op, map, NULL, 0);
00200         return; /* no valid matches? if so, return */
00201     }
00202 
00203     /* Next make a choice, and loop through until we get to it */
00204     choice = rndm(0, numat-1);
00205     for (at = first_archetype; at != NULL; at = at->next)
00206         if ((QUERY_FLAG((&at->clone), FLAG_MONSTER) == QUERY_FLAG(op, FLAG_MONSTER)) && (find_free_spot(&at->clone, map, x, y, 0, SIZEOFFREE) != -1)) {
00207             if (!choice)
00208                 break;
00209             else
00210                 choice--;
00211         }
00212 
00213     /* Look through the monster.  Unapply anything they have applied,
00214      * and remove any spells.  Note that if this is extended
00215      * to players, that would need to get fixed somehow.
00216      */
00217     for (tmp = op->inv; tmp != NULL; tmp = next) {
00218         next = tmp->below;
00219         if (QUERY_FLAG(tmp, FLAG_APPLIED))
00220             manual_apply(op, tmp, 0);
00221         if (tmp->type == SPELL) {
00222             remove_ob(tmp);
00223             free_object(tmp);
00224         }
00225     }
00226 
00227     /* Preserve some values for the new object */
00228     owner = get_owner(op);
00229     friendly = QUERY_FLAG(op, FLAG_FRIENDLY);
00230     if (friendly)
00231         remove_friendly_object(op);
00232 
00233     copy_object(&(at->clone), op);
00234     if (owner != NULL)
00235         set_owner(op, owner);
00236     if (friendly) {
00237         SET_FLAG(op, FLAG_FRIENDLY);
00238         op->attack_movement = PETMOVE;
00239         add_friendly_object(op);
00240     } else
00241         CLEAR_FLAG(op, FLAG_FRIENDLY);
00242 
00243     /* Put the new creature on the map */
00244     op->x = x;
00245     op->y = y;
00246     if ((op = insert_ob_in_map(op, map, owner, 0)) == NULL)
00247         return;
00248 
00249     if (HAS_RANDOM_ITEMS(op))
00250         /* No GT_APPLY here because we'll do it manually. */
00251         create_treasure(op->randomitems, op, GT_INVISIBLE, map->difficulty, 0);
00252 
00253     /* Apply any objects. */
00254     for (tmp = op->inv; tmp != NULL; tmp = next) {
00255         next = tmp->below;
00256         monster_check_apply(op, tmp);
00257     }
00258 }
00259 
00260 
00272 static void polymorph_melt(object *who, object *op) {
00273     /* Not unique */
00274     char name[MAX_BUF];
00275 
00276     query_name(op, name, MAX_BUF);
00277     if (op->nrof > 1)
00278         draw_ext_info_format(NDI_GREY, 0, who, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
00279                              "The %s glow red, melt and evaporate!",
00280                              "The %s glow red, melt and evaporate!",
00281                              name);
00282     else
00283         draw_ext_info_format(NDI_GREY, 0, who, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
00284                              "The %s glows red, melts and evaporates!",
00285                              "The %s glows red, melts and evaporates!",
00286                              name);
00287     play_sound_map(SOUND_TYPE_ITEM, op, 0, "evaporate");
00288     remove_ob(op);
00289     free_object(op);
00290     return;
00291 }
00292 
00302 static void polymorph_item(object *who, object *op, int level) {
00303     archetype *at;
00304     int max_value, difficulty, tries = 0, choice, charges = op->stats.food, numat = 0;
00305     object *new_ob;
00306 
00307     /* We try and limit the maximum value of the changed object. */
00308     max_value = op->value*2;
00309     if (max_value > 2000*(level/10))
00310         max_value = 2000*(level/10)+(max_value-2000*(level/10))/3;
00311 
00312     /* Look through and try to find matching items.  Can't turn into something
00313      * invisible.  Also, if the value is too high now, it would almost
00314      * certainly be too high below.
00315      */
00316     for (at = first_archetype; at != NULL; at = at->next) {
00317         if (at->clone.type == op->type
00318         && !at->clone.invisible
00319         && at->clone.value > 0
00320         && at->clone.value < max_value
00321         && !QUERY_FLAG(&at->clone, FLAG_NO_DROP)
00322         && !QUERY_FLAG(&at->clone, FLAG_STARTEQUIP))
00323             numat++;
00324     }
00325 
00326     if (!numat)
00327         return;
00328 
00329     difficulty = op->magic*5;
00330     if (difficulty < 0)
00331         difficulty = 0;
00332     new_ob = get_object();
00333     do {
00334         choice = rndm(0, numat-1);
00335         for (at = first_archetype; at != NULL; at = at->next) {
00336             if (at->clone.type == op->type
00337             && !at->clone.invisible
00338             && at->clone.value > 0
00339             && at->clone.value < max_value
00340             && !QUERY_FLAG(&at->clone, FLAG_NO_DROP)
00341             && !QUERY_FLAG(&at->clone, FLAG_STARTEQUIP)) {
00342                 if (!choice)
00343                     break;
00344                 else
00345                     choice--;
00346             }
00347         }
00348         copy_object(&(at->clone), new_ob);
00349         fix_generated_item(new_ob, op, difficulty, FABS(op->magic), GT_ENVIRONMENT);
00350         ++tries;
00351     } while (new_ob->value > max_value && tries < 10);
00352     if (new_ob->invisible) {
00353         LOG(llevError, "polymorph_item: fix_generated_object made %s invisible?!\n", new_ob->name);
00354         free_object(new_ob);
00355         return;
00356     }
00357 
00358     /* Unable to generate an acceptable item?  Melt it */
00359     if (tries == 10) {
00360         polymorph_melt(who, op);
00361         free_object(new_ob);
00362         return;
00363     }
00364 
00365     if (op->nrof && new_ob->nrof) {
00366         new_ob->nrof = op->nrof;
00367         /* decrease the number of items */
00368         if (new_ob->nrof > 2)
00369             new_ob->nrof -= rndm(0, op->nrof/2-1);
00370     }
00371 
00372     /* We don't want rings to keep sustenance/hungry status. There are probably
00373      *  other cases too that should be checked.
00374      */
00375     if (charges && op->type != RING && op->type != FOOD)
00376         op->stats.food = charges;
00377 
00378     new_ob->x = op->x;
00379     new_ob->y = op->y;
00380     remove_ob(op);
00381     free_object(op);
00382     /*
00383      * Don't want objects merged or re-arranged, as it then messes up the
00384      * order
00385      */
00386     insert_ob_in_map(new_ob, who->map, new_ob, INS_NO_MERGE|INS_NO_WALK_ON);
00387 }
00388 
00399 void polymorph(object *op, object *who, int level) {
00400     int tmp;
00401 
00402     /* Can't polymorph players right now */
00403     /* polymorphing generators opens up all sorts of abuses */
00404     if (op->type == PLAYER || QUERY_FLAG(op, FLAG_GENERATOR))
00405         return;
00406 
00407     if (QUERY_FLAG(op, FLAG_MONSTER)) {
00408         polymorph_living(op, level);
00409         return;
00410     }
00411     /* If it is a living object of some other type, don't handle
00412      * it now.
00413      */
00414     if (QUERY_FLAG(op, FLAG_ALIVE))
00415         return;
00416 
00417     /* Don't want to morph flying arrows, etc... */
00418     if (FABS(op->speed) > 0.001 && !QUERY_FLAG(op, FLAG_ANIMATE))
00419         return;
00420 
00421     /* Do some sanity checking here.  type=0 is unknown, objects
00422      * without archetypes are not good.  As are a few other
00423      * cases.
00424      */
00425     if (op->type == 0
00426     || op->arch == NULL
00427     || QUERY_FLAG(op, FLAG_NO_PICK)
00428     || op->move_block
00429     || op->type == TREASURE)
00430         return;
00431 
00432     tmp = rndm(0, 7);
00433     if (tmp)
00434         polymorph_item(who, op, level);
00435     else
00436         polymorph_melt(who, op);
00437 }
00438 
00439 
00453 int cast_polymorph(object *op, object *caster, object *spell_ob, int dir) {
00454     object *tmp, *next;
00455     int range, mflags, maxrange, level;
00456     mapstruct *m;
00457 
00458     if (dir == 0)
00459         return 0;
00460 
00461     maxrange = spell_ob->range+SP_level_range_adjust(caster, spell_ob);
00462     level = caster_level(caster, spell_ob);
00463     for (range = 1; range < maxrange; range++) {
00464         sint16 x = op->x+freearr_x[dir]*range, y = op->y+freearr_y[dir]*range;
00465         object *image;
00466 
00467         m = op->map;
00468         mflags = get_map_flags(m, &m, x, y, &x, &y);
00469 
00470         if (mflags&(P_NO_MAGIC|P_OUT_OF_MAP))
00471             break;
00472 
00473         if (GET_MAP_MOVE_BLOCK(m, x, y)&MOVE_FLY_LOW)
00474             break;
00475 
00476         /* Get the top most object */
00477         for (tmp = GET_MAP_OB(m, x, y); tmp != NULL && tmp->above != NULL; tmp = tmp->above)
00478             ;
00479 
00480         /* Now start polymorphing the objects, top down */
00481         while (tmp != NULL) {
00482             /* Once we find the floor, no need to go further */
00483             if (QUERY_FLAG(tmp, FLAG_IS_FLOOR))
00484                 break;
00485             next = tmp->below;
00486             polymorph(tmp, op, level);
00487             tmp = next;
00488         }
00489         image = arch_to_object(spell_ob->other_arch);
00490         image->x = x;
00491         image->y = y;
00492         image->stats.food = 5;
00493         image->speed_left = 0.1;
00494         insert_ob_in_map(image, m, op, 0);
00495     }
00496     return 1;
00497 }
00498 
00525 int cast_create_missile(object *op, object *caster, object *spell, int dir, const char *stringarg) {
00526     int missile_plus = 0, bonus_plus = 0;
00527     const char *missile_name;
00528     object *tmp, *missile;
00529     tag_t tag;
00530 
00531     missile_name = "arrow";
00532 
00533     for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
00534         if (tmp->type == BOW && QUERY_FLAG(tmp, FLAG_APPLIED))
00535             missile_name = tmp->race;
00536 
00537     missile_plus = spell->stats.dam+SP_level_dam_adjust(caster, spell);
00538 
00539     if (!strcmp(missile_name, "arrows"))
00540         missile_name = "arrow";
00541     else if (!strcmp(missile_name, "crossbow bolts"))
00542         missile_name = "bolt";
00543 
00544     if (find_archetype(missile_name) == NULL) {
00545         LOG(llevDebug, "Cast create_missile: could not find archetype %s\n", missile_name);
00546         return 0;
00547     }
00548     missile = create_archetype(missile_name);
00549 
00550     if (stringarg) {
00551         /* If it starts with a letter, presume it is a description */
00552         if (isalpha(*stringarg)) {
00553             artifact *al = find_artifactlist(missile->type)->items;
00554 
00555             for (; al != NULL; al = al->next)
00556                 if (!strcasecmp(al->item->name, stringarg))
00557                     break;
00558 
00559             if (!al) {
00560                 free_object(missile);
00561                 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
00562                                      "No such object %ss of %s",
00563                                      "No such object %ss of %s",
00564                                      missile_name, stringarg);
00565                 return 0;
00566             }
00567             if (al->item->slaying) {
00568                 free_object(missile);
00569                 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
00570                                      "You are not allowed to create %ss of %s",
00571                                      "You are not allowed to create %ss of %s",
00572                                      missile_name, stringarg);
00573                 return 0;
00574             }
00575             give_artifact_abilities(missile, al->item);
00576             /* These special arrows cost something extra.  Don't have them also be
00577             * magical - otherwise, in most cases, not enough will be created.
00578             * I don't want to get into the parsing of having to do both plus and
00579             * type.
00580             */
00581             bonus_plus = 1+(al->item->value/5);
00582             missile_plus = 0;
00583         } else if (atoi(stringarg) < missile_plus)
00584             missile_plus = atoi(stringarg);
00585     }
00586     if (missile_plus > 4)
00587         missile_plus = 4;
00588     else if (missile_plus < -4)
00589         missile_plus = -4;
00590 
00591     missile->nrof = spell->duration+SP_level_duration_adjust(caster, spell);
00592     if (missile->nrof <= 3*(missile_plus+bonus_plus)) {
00593         free_object(missile);
00594         draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
00595                              "This item is too powerful for you to create!",
00596                              NULL);
00597         return 0;
00598     }
00599     missile->nrof -= 3*(missile_plus+bonus_plus);
00600     if (missile->nrof < 1)
00601         missile->nrof = 1;
00602 
00603     missile->magic = missile_plus;
00604     /* Can't get any money for these objects */
00605     missile->value = 0;
00606 
00607     SET_FLAG(missile, FLAG_IDENTIFIED);
00608     tag = missile->count;
00609 
00610     if (!cast_create_obj(op, missile, dir)
00611     && op->type == PLAYER
00612     && !was_destroyed(missile, tag)) {
00613         pick_up(op, missile);
00614     }
00615     return 1;
00616 }
00617 
00618 
00639 int cast_create_food(object *op, object *caster, object *spell_ob, int dir, const char *stringarg) {
00640     int food_value;
00641     archetype *at = NULL;
00642     object *new_op;
00643 
00644     food_value = spell_ob->stats.food+50*SP_level_duration_adjust(caster, spell_ob);
00645 
00646     if (stringarg) {
00647         at = find_archetype_by_object_type_name(FOOD, stringarg);
00648         if (at == NULL)
00649             at = find_archetype_by_object_type_name(DRINK, stringarg);
00650         if (at == NULL || at->clone.stats.food > food_value)
00651             stringarg = NULL;
00652     }
00653 
00654     if (!stringarg) {
00655         archetype *at_tmp;
00656 
00657         /* We try to find the archetype with the maximum food value.
00658          * This removes the dependancy of hard coded food values in this
00659          * function, and addition of new food types is automatically added.
00660          * We don't use flesh types because the weight values of those need
00661          * to be altered from the donor.
00662          */
00663 
00664         /* We assume the food items don't have multiple parts */
00665         for (at_tmp = first_archetype; at_tmp != NULL; at_tmp = at_tmp->next) {
00666             if (at_tmp->clone.type == FOOD || at_tmp->clone.type == DRINK) {
00667                 /* Basically, if the food value is something that is creatable
00668                  * under the limits of the spell and it is higher than
00669                  * the item we have now, take it instead.
00670                  */
00671                 if (at_tmp->clone.stats.food <= food_value
00672                 && (!at || at_tmp->clone.stats.food > at->clone.stats.food))
00673                     at = at_tmp;
00674             }
00675         }
00676     }
00677     /* Pretty unlikely (there are some very low food items), but you never
00678      * know
00679      */
00680     if (!at) {
00681         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
00682                       "You don't have enough experience to create any food.", NULL);
00683         return 0;
00684     }
00685 
00686     food_value /= at->clone.stats.food;
00687     new_op = get_object();
00688     copy_object(&at->clone, new_op);
00689     new_op->nrof = food_value;
00690 
00691     new_op->value = 0;
00692     if (new_op->nrof < 1)
00693         new_op->nrof = 1;
00694 
00695     cast_create_obj(op, new_op, dir);
00696     return 1;
00697 }
00698 
00715 int probe(object *op, object *caster, object *spell_ob, int dir) {
00716     int r, mflags, maxrange;
00717     object *tmp;
00718     mapstruct *m;
00719 
00720     if (!dir) {
00721         examine_monster(op, op);
00722         return 1;
00723     }
00724     maxrange = spell_ob->range+SP_level_range_adjust(caster, spell_ob);
00725     for (r = 1; r < maxrange; r++) {
00726         sint16 x = op->x+r*freearr_x[dir], y = op->y+r*freearr_y[dir];
00727 
00728         m = op->map;
00729         mflags = get_map_flags(m, &m, x, y, &x, &y);
00730 
00731         if (mflags&P_OUT_OF_MAP)
00732             break;
00733 
00734         if (!QUERY_FLAG(op, FLAG_WIZCAST) && (mflags&P_NO_MAGIC)) {
00735             draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
00736                           "Something blocks your magic.", NULL);
00737             return 0;
00738         }
00739         if (mflags&P_IS_ALIVE) {
00740             for (tmp = GET_MAP_OB(m, x, y); tmp != NULL; tmp = tmp->above)
00741                 if (QUERY_FLAG(tmp, FLAG_ALIVE)&&(tmp->type == PLAYER || QUERY_FLAG(tmp, FLAG_MONSTER))) {
00742                     draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_SUCCESS,
00743                                   "You detect something.", NULL);
00744                     if (tmp->head != NULL)
00745                         tmp = tmp->head;
00746                     examine_monster(op, tmp);
00747                     return 1;
00748                 }
00749         }
00750     }
00751     draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
00752                   "You detect nothing.", NULL);
00753     return 1;
00754 }
00755 
00756 
00774 int makes_invisible_to(object *pl, object *mon) {
00775     if (!pl->invisible)
00776         return 0;
00777     if (pl->type == PLAYER) {
00778         /* If race isn't set, then invisible unless it is undead */
00779         if (!pl->contr->invis_race) {
00780             if (QUERY_FLAG(mon, FLAG_UNDEAD))
00781                 return 0;
00782             return 1;
00783         }
00784         /* invis_race is set if we get here */
00785         if (!strcmp(pl->contr->invis_race, "undead") && is_true_undead(mon))
00786             return 1;
00787         /* No race, can't be invisible to it */
00788         if (!mon->race)
00789             return 0;
00790         if (strstr(mon->race, pl->contr->invis_race))
00791             return 1;
00792         /* Nothing matched above, return 0 */
00793         return 0;
00794     } else {
00795         /* monsters are invisible to everything */
00796         return 1;
00797     }
00798 }
00799 
00821 int cast_invisible(object *op, object *caster, object *spell_ob) {
00822     object *tmp;
00823 
00824     if (op->invisible > 1000) {
00825         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
00826                       "You can not extend the duration of your invisibility any further", NULL);
00827         return 0;
00828     }
00829 
00830     /* Remove the switch with 90% duplicate code - just handle the differences with
00831      * and if statement or two.
00832      */
00833     op->invisible += spell_ob->duration+SP_level_duration_adjust(caster, spell_ob);
00834     /* max duration */
00835     if (op->invisible > 1000)
00836         op->invisible = 1000;
00837 
00838     if (op->type == PLAYER) {
00839         if (op->contr->invis_race)
00840             FREE_AND_CLEAR_STR(op->contr->invis_race);
00841         if (spell_ob->race)
00842             op->contr->invis_race = add_refcount(spell_ob->race);
00843         if (QUERY_FLAG(spell_ob, FLAG_MAKE_INVIS))
00844             op->contr->tmp_invis = 0;
00845         else
00846             op->contr->tmp_invis = 1;
00847 
00848         op->contr->hidden = 0;
00849     }
00850     if (makes_invisible_to(op, op))
00851         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_SUCCESS,
00852                       "You can't see your hands!", NULL);
00853     else
00854         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_SUCCESS,
00855                       "You feel more transparent!", NULL);
00856 
00857     update_object(op, UP_OBJ_FACE);
00858 
00859     /* Only search the active objects - only these should actually do
00860      * harm to the player.
00861      */
00862     for (tmp = active_objects; tmp != NULL; tmp = tmp->active_next)
00863         if (tmp->enemy == op)
00864             tmp->enemy = NULL;
00865     return 1;
00866 }
00867 
00882 int cast_earth_to_dust(object *op, object *caster, object *spell_ob) {
00883     object *tmp, *next;
00884     int range, i, j, mflags;
00885     sint16 sx, sy;
00886     mapstruct *m;
00887 
00888     if (op->type != PLAYER)
00889         return 0;
00890 
00891     range = spell_ob->range+SP_level_range_adjust(caster, spell_ob);
00892 
00893     for (i = -range; i < range; i++)
00894         for (j = -range; j < range; j++) {
00895             sx = op->x+i;
00896             sy = op->y+j;
00897             m = op->map;
00898             mflags = get_map_flags(m, &m, sx, sy, &sx, &sy);
00899 
00900             if (mflags&P_OUT_OF_MAP)
00901                 continue;
00902 
00903             /* If the space doesn't block, no wall here to remove
00904              * Don't care too much what it blocks - this allows for
00905              * any sort of earthwall/airwall/waterwall, etc
00906              * type effects.
00907              */
00908             if (GET_MAP_MOVE_BLOCK(m, sx, sy)) {
00909                 for (tmp = GET_MAP_OB(m, sx, sy); tmp != NULL; tmp = next) {
00910                     next = tmp->above;
00911                     if (tmp && QUERY_FLAG(tmp, FLAG_TEAR_DOWN))
00912                         hit_player(tmp, 9998, op, AT_PHYSICAL, 0);
00913                 }
00914             }
00915         }
00916     return 1;
00917 }
00918 
00935 int cast_word_of_recall(object *op, object *caster, object *spell_ob) {
00936     object *dummy;
00937     int time;
00938 
00939     if (op->type != PLAYER)
00940         return 0;
00941 
00942     if (find_obj_by_type_subtype(op, SPELL_EFFECT, SP_WORD_OF_RECALL)) {
00943         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_SUCCESS,
00944                       "You feel a force starting to build up inside you.", NULL);
00945         return 1;
00946     }
00947 
00948     dummy = create_archetype(FORCE_NAME);
00949     if (dummy == NULL) {
00950         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
00951                       "Oops, program error!", NULL);
00952         LOG(llevError, "cast_word_of_recall: create_archetype(force) failed!\n");
00953         return 0;
00954     }
00955     time = spell_ob->duration-SP_level_duration_adjust(caster, spell_ob);
00956     if (time < 1)
00957         time = 1;
00958 
00959     /* value of speed really doesn't make much difference, as long as it is
00960      * positive.  Lower value may be useful so that the problem doesn't
00961      * do anything really odd if it say a -1000 or something.
00962      */
00963     dummy->speed = 0.002;
00964     update_ob_speed(dummy);
00965     dummy->speed_left = -dummy->speed*time;
00966     dummy->type = SPELL_EFFECT;
00967     dummy->subtype = SP_WORD_OF_RECALL;
00968 
00969     /* If we could take advantage of enter_player_savebed() here, it would be
00970      * nice, but until the map load fails, we can't.
00971      */
00972     EXIT_PATH(dummy) = add_string(op->contr->savebed_map);
00973     EXIT_X(dummy) = op->contr->bed_x;
00974     EXIT_Y(dummy) = op->contr->bed_y;
00975 
00976     (void)insert_ob_in_ob(dummy, op);
00977     draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_SUCCESS,
00978                   "You feel a force starting to build up inside you.", NULL);
00979     return 1;
00980 }
00981 
00997 int cast_wonder(object *op, object *caster, int dir, object *spell_ob) {
00998     object *newspell;
00999 
01000     if (!rndm(0, 3))
01001         return cast_cone(op, caster, dir, spell_ob);
01002 
01003     if (spell_ob->randomitems) {
01004         newspell = generate_treasure(spell_ob->randomitems, caster->level);
01005         if (!newspell) {
01006             LOG(llevError, "cast_wonder: Unable to get a spell!\n");
01007             return 0;
01008         }
01009         if (newspell->type != SPELL) {
01010             LOG(llevError, "cast_wonder: spell returned is not a spell (%d, %s)!\n", newspell->type, newspell->name);
01011             return 0;
01012         }
01013         /* Prevent inifinit recursion */
01014         if (newspell->subtype == SP_WONDER) {
01015             LOG(llevError, "cast_wonder: spell returned is another wonder spell!\n");
01016             return 0;
01017         }
01018         return cast_spell(op, caster, dir, newspell, NULL);
01019     }
01020     return 1;
01021 }
01022 
01031 int perceive_self(object *op) {
01032     char cp[VERY_BIG_BUF], buf[MAX_BUF];
01033     archetype *at = find_archetype(ARCH_DEPLETION);
01034     object *tmp;
01035     const object *god;
01036     int i;
01037 
01038     describe_item(op, op, cp, VERY_BIG_BUF);
01039 
01040     god = find_god(determine_god(op));
01041     if (god)
01042         draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_PERCEIVE_SELF,
01043                              "You worship %s",
01044                              "You worship %s",
01045                              god->name);
01046     else
01047         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_PERCEIVE_SELF,
01048                       "You worship no god", NULL);
01049 
01050     tmp = present_arch_in_ob(at, op);
01051 
01052     if (*cp == '\0' && tmp == NULL)
01053         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_PERCEIVE_SELF,
01054                       "You feel very mundane", NULL);
01055     else {
01056         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_PERCEIVE_SELF,
01057                       "You have:", NULL);
01058         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_PERCEIVE_SELF,
01059                       cp, cp);
01060         if (tmp != NULL) {
01061             for (i = 0; i < NUM_STATS; i++) {
01062                 if (get_attr_value(&tmp->stats, i) < 0) {
01063                     draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_PERCEIVE_SELF,
01064                                          "Your %s is depleted by %d",
01065                                          "Your %s is depleted by %d",
01066                                          statname[i], -(get_attr_value(&tmp->stats, i)));
01067                 }
01068             }
01069         }
01070     }
01071     if (op->glow_radius > 0)
01072         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_PERCEIVE_SELF,
01073                       "You glow in the dark.", NULL);
01074 
01075     if (is_dragon_pl(op)) {
01076         /* now grab the 'dragon_ability'-force from the player's inventory */
01077         for (tmp = op->inv; tmp != NULL; tmp = tmp->below) {
01078             if (tmp->type == FORCE && !strcmp(tmp->arch->name, "dragon_ability_force")) {
01079                 if (tmp->stats.exp == 0) {
01080                     snprintf(buf, sizeof(buf), "Your metabolism isn't focused on anything.");
01081                 } else {
01082                     snprintf(buf, sizeof(buf), "Your metabolism is focused on %s.", change_resist_msg[tmp->stats.exp]);
01083                 }
01084                 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_PERCEIVE_SELF,
01085                               buf, buf);
01086                 break;
01087             }
01088         }
01089     }
01090     return 1;
01091 }
01092 
01122 int cast_create_town_portal(object *op, object *caster, object *spell, int dir) {
01123     object *dummy, *force, *old_force, *tmp;
01124     archetype *perm_portal;
01125     char portal_name [1024], portal_message [1024];
01126     sint16 exitx, exity;
01127     mapstruct *exitmap;
01128     int op_level;
01129 
01130     /* Check to see if the map the player is currently on is a per player unique
01131      * map.  This can be determined in that per player unique maps have the
01132      * full pathname listed. Ignore if settings.create_home_portals is true.
01133      */
01134     if (!settings.create_home_portals) {
01135         if (!strncmp(op->map->path, settings.localdir, strlen(settings.localdir))) {
01136             draw_ext_info(NDI_UNIQUE|NDI_NAVY, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
01137                           "You can't cast that here.", NULL);
01138             return 0;
01139         }
01140     }
01141 
01142     /* Check to see if the player is on a transport */
01143     if (op->contr && op->contr->transport) {
01144         draw_ext_info(NDI_UNIQUE|NDI_NAVY, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
01145                       "You need to exit the transport to cast that.", NULL);
01146         return 0;
01147     }
01148 
01149     /* The first thing to do is to check if we have a marked destination
01150      * dummy is used to make a check inventory for the force
01151      */
01152     dummy = arch_to_object(spell->other_arch);
01153     if (dummy == NULL) {
01154         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
01155                       "Oops, program error!", NULL);
01156         LOG(llevError, "get_object failed (force in cast_create_town_portal for %s!\n", op->name);
01157         return 0;
01158     }
01159     force = check_inv_recursive(op, dummy);
01160 
01161     if (force == NULL) {
01162         /* Here we know there is no destination marked up.
01163          * We have 2 things to do:
01164          * 1. Mark the destination in the player inventory.
01165          * 2. Let the player know it worked.
01166          */
01167         free_string(dummy->name);
01168         dummy->name = add_string(op->map->path);
01169         EXIT_X(dummy) = op->x;
01170         EXIT_Y(dummy) = op->y;
01171         dummy->weapontype = op->map->last_reset_time.tv_sec;
01172         insert_ob_in_ob(dummy, op);
01173         draw_ext_info(NDI_UNIQUE|NDI_NAVY, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_SUCCESS,
01174                       "You fix this place in your mind and feel that you"
01175                       "can come here from anywhere.",
01176                       NULL);
01177         return 1;
01178     }
01179     free_object(dummy);
01180 
01181     /* Here we know where the town portal should go to
01182      * We should kill any existing portal associated with the player.
01183      * Than we should create the 2 portals.
01184      * For each of them, we need:
01185      *    - To create the portal with the name of the player+destination map
01186      *    - set the owner of the town portal
01187      *    - To mark the position of the portal in the player's inventory
01188      *      for easier destruction.
01189      *
01190      *  The mark works has follow:
01191      *   slaying: Existing town portal
01192      *   hp, sp : x & y of the associated portal
01193      *   name   : name of the portal
01194      *   race   : map the portal is in
01195      */
01196 
01197     /* First step: killing existing town portals */
01198     dummy = create_archetype(spell->race);
01199     if (dummy == NULL) {
01200         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
01201                       "Oops, program error!", NULL);
01202         LOG(llevError, "get_object failed (force) in cast_create_town_portal for %s!\n", op->name);
01203         return 0;
01204     }
01205     perm_portal = find_archetype(spell->slaying);
01206 
01207     /* To kill a town portal, we go trough the player's inventory,
01208      * for each marked portal in player's inventory,
01209      *   -We try load the associated map (if impossible, consider the portal destructed)
01210      *   -We find any portal in the specified location.
01211      *      If it has the good name, we destruct it.
01212      *   -We destruct the force indicating that portal.
01213      */
01214     while ((old_force = check_inv_recursive(op, dummy))) {
01215         exitx = EXIT_X(old_force);
01216         exity = EXIT_Y(old_force);
01217         LOG(llevDebug, "Trying to kill a portal in %s (%d,%d)\n", old_force->race, exitx, exity);
01218 
01219         if (!strncmp(old_force->race, settings.localdir, strlen(settings.localdir)))
01220             exitmap = ready_map_name(old_force->race, MAP_PLAYER_UNIQUE);
01221         else
01222             exitmap = ready_map_name(old_force->race, 0);
01223 
01224         if (exitmap) {
01225             tmp = present_arch(perm_portal, exitmap, exitx, exity);
01226             while (tmp) {
01227                 if (tmp->name == old_force->name) {
01228                     remove_ob(tmp);
01229                     free_object(tmp);
01230                     break;
01231                 } else {
01232                     tmp = tmp->above;
01233                 }
01234             }
01235         }
01236         remove_ob(old_force);
01237         free_object(old_force);
01238         LOG(llevDebug, "\n");
01239     }
01240     free_object(dummy);
01241 
01242     /* Creating the portals.
01243      * The very first thing to do is to ensure
01244      * access to the destination map.
01245      * If we can't, don't fizzle. Simply warn player.
01246      * This ensure player pays his mana for the spell
01247      * because HE is responsible of forgotting.
01248      * 'force' is the destination of the town portal, which we got
01249      * from the players inventory above.
01250      */
01251 
01252     /* Ensure exit map is loaded*/
01253     if (!strncmp(force->name, settings.localdir, strlen(settings.localdir)))
01254         exitmap = ready_map_name(force->name, MAP_PLAYER_UNIQUE);
01255     else
01256         exitmap = ready_map_name(force->name, 0);
01257 
01258     /* If we were unable to load (ex. random map deleted), warn player*/
01259     if (exitmap == NULL) {
01260         draw_ext_info(NDI_UNIQUE|NDI_NAVY, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01261                       "Something strange happens. You can't remember where to go!?",
01262                       NULL);
01263         remove_ob(force);
01264         free_object(force);
01265         return 1;
01266     } else if (exitmap->last_reset_time.tv_sec != force->weapontype) {
01267         draw_ext_info(NDI_UNIQUE|NDI_NAVY, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01268                       "The spell effect has expired.", NULL);
01269         remove_ob(force);
01270         free_object(force);
01271         return 1;
01272     }
01273 
01274     op_level = caster_level(caster, spell);
01275     if (op_level < 15)
01276         snprintf(portal_message, 1024, "\nThe air moves around you and\na huge smell of ammonia\nsurounds you as you pass\nthrough %s's tiny portal\nPouah!\n", op->name);
01277     else if (op_level < 30)
01278         snprintf(portal_message, 1024, "\n%s's portal smells of ozone.\nYou do a lot of movements and finally pass\nthrough the small hole in the air\n", op->name);
01279     else if (op_level < 60)
01280         snprintf(portal_message, 1024, "\nA shining door opens in the air in front of you,\nshowing you the path to another place.\n");
01281     else
01282         snprintf(portal_message, 1024, "\nAs you walk through %s's portal, flowers come out\nfrom the ground around you.\nYou feel awed.\n", op->name);
01283 
01284     /* Create a portal in front of player
01285      * dummy contain the portal and
01286      * force contain the track to kill it later
01287      */
01288 
01289     snprintf(portal_name, 1024, "%s's portal to %s", op->name, force->name);
01290     dummy = create_archetype(spell->slaying); /*The portal*/
01291     if (dummy == NULL) {
01292         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
01293                       "Oops, program error!", NULL);
01294         LOG(llevError, "get_object failed (perm_magic_portal) in cast_create_town_portal for %s!\n", op->name);
01295         return 0;
01296     }
01297     EXIT_PATH(dummy) = add_string(force->name);
01298     EXIT_X(dummy) = EXIT_X(force);
01299     EXIT_Y(dummy) = EXIT_Y(force);
01300     FREE_AND_COPY(dummy->name, portal_name);
01301     FREE_AND_COPY(dummy->name_pl, portal_name);
01302     dummy->msg = add_string(portal_message);
01303     dummy->race = add_string(op->name);   /*Save the owner of the portal*/
01304     cast_create_obj(op, dummy, 0);
01305 
01306     /* Now we need to to create a town portal marker inside the player
01307      * object, so on future castings, we can know that he has an active
01308      * town portal.
01309      */
01310     tmp = create_archetype(spell->race);
01311     if (tmp == NULL) {
01312         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
01313                       "Oops, program error!", NULL);
01314         LOG(llevError, "get_object failed (force) in cast_create_town_portal for %s!\n", op->name);
01315         return 0;
01316     }
01317     tmp->race = add_string(op->map->path);
01318     FREE_AND_COPY(tmp->name, portal_name);
01319     EXIT_X(tmp) = dummy->x;
01320     EXIT_Y(tmp) = dummy->y;
01321     insert_ob_in_ob(tmp, op);
01322 
01323     /* Create a portal in the destination map
01324      * dummy contain the portal and
01325      * force the track to kill it later
01326      * the 'force' variable still contains the 'reminder' of
01327      * where this portal goes to.
01328      */
01329     snprintf(portal_name, 1024, "%s's portal to %s", op->name, op->map->path);
01330     dummy = create_archetype(spell->slaying);  /*The portal*/
01331     if (dummy == NULL) {
01332         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
01333                       "Oops, program error!", NULL);
01334         LOG(llevError, "get_object failed (perm_magic_portal) in cast_create_town_portal for %s!\n", op->name);
01335         return 0;
01336     }
01337     EXIT_PATH(dummy) = add_string(op->map->path);
01338     EXIT_X(dummy) = op->x;
01339     EXIT_Y(dummy) = op->y;
01340     FREE_AND_COPY(dummy->name, portal_name);
01341     FREE_AND_COPY(dummy->name_pl, portal_name);
01342     dummy->msg = add_string(portal_message);
01343     dummy->x = EXIT_X(force);
01344     dummy->y = EXIT_Y(force);
01345     dummy->race = add_string(op->name);   /*Save the owner of the portal*/
01346     insert_ob_in_map(dummy, exitmap, op, 0);
01347 
01348     /* Now we create another town portal marker that
01349      * points back to the one we just made
01350      */
01351     tmp = create_archetype(spell->race);
01352     if (tmp == NULL) {
01353         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
01354                       "Oops, program error!", NULL);
01355         LOG(llevError, "get_object failed (force) in cast_create_town_portal for %s!\n", op->name);
01356         return 0;
01357     }
01358     tmp->race = add_string(force->name);
01359     FREE_AND_COPY(tmp->name, portal_name);
01360     EXIT_X(tmp) = dummy->x;
01361     EXIT_Y(tmp) = dummy->y;
01362     insert_ob_in_ob(tmp, op);
01363 
01364     /* Describe the player what happened
01365      */
01366     draw_ext_info(NDI_UNIQUE|NDI_NAVY, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_SUCCESS,
01367                   "You see air moving and showing you the way home.", NULL);
01368     remove_ob(force); /* Delete the force inside the player*/
01369     free_object(force);
01370     return 1;
01371 }
01372 
01373 
01391 int magic_wall(object *op, object *caster, int dir, object *spell_ob) {
01392     object *tmp, *tmp2;
01393     int i, posblocked, negblocked, maxrange;
01394     sint16 x, y;
01395     mapstruct *m;
01396     const char *name;
01397     archetype *at;
01398 
01399     if (!dir) {
01400         dir = op->facing;
01401         x = op->x;
01402         y = op->y;
01403     } else {
01404         x = op->x+freearr_x[dir];
01405         y = op->y+freearr_y[dir];
01406     }
01407     m = op->map;
01408 
01409     if ((spell_ob->move_block || x != op->x || y != op->y)
01410     && (get_map_flags(m, &m, x, y, &x, &y)&(P_OUT_OF_MAP|P_IS_ALIVE)
01411     || ((spell_ob->move_block&GET_MAP_MOVE_BLOCK(m, x, y)) == spell_ob->move_block))) {
01412         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
01413                       "Something is in the way.", NULL);
01414         return 0;
01415     }
01416     if (spell_ob->other_arch) {
01417         tmp = arch_to_object(spell_ob->other_arch);
01418     } else if (spell_ob->race) {
01419         char buf1[MAX_BUF];
01420 
01421         snprintf(buf1, sizeof(buf1), spell_ob->race, dir);
01422         at = find_archetype(buf1);
01423         if (!at) {
01424             LOG(llevError, "summon_wall: Unable to find archetype %s\n", buf1);
01425             draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
01426                           "This spell is broken.", NULL);
01427             return 0;
01428         }
01429         tmp = arch_to_object(at);
01430     } else {
01431         LOG(llevError, "magic_wall: spell %s lacks other_arch\n", spell_ob->name);
01432         return 0;
01433     }
01434 
01435     if (tmp->type == SPELL_EFFECT) {
01436         tmp->attacktype = spell_ob->attacktype;
01437         tmp->duration = spell_ob->duration+SP_level_duration_adjust(caster, spell_ob);
01438         tmp->stats.dam = spell_ob->stats.dam+SP_level_dam_adjust(caster, spell_ob);
01439         tmp->range = 0;
01440     } else if (QUERY_FLAG(tmp, FLAG_ALIVE)) {
01441         tmp->stats.hp = spell_ob->duration+SP_level_duration_adjust(caster, spell_ob);
01442         tmp->stats.maxhp = tmp->stats.hp;
01443         set_owner(tmp, op);
01444         set_spell_skill(op, caster, spell_ob, tmp);
01445     }
01446     if (QUERY_FLAG(spell_ob, FLAG_IS_USED_UP) || QUERY_FLAG(tmp, FLAG_IS_USED_UP)) {
01447         tmp->stats.food = spell_ob->duration+SP_level_duration_adjust(caster, spell_ob);
01448         SET_FLAG(tmp, FLAG_IS_USED_UP);
01449     }
01450     if (QUERY_FLAG(spell_ob, FLAG_TEAR_DOWN)) {
01451         tmp->stats.hp = spell_ob->stats.dam+SP_level_dam_adjust(caster, spell_ob);
01452         tmp->stats.maxhp = tmp->stats.hp;
01453         SET_FLAG(tmp, FLAG_TEAR_DOWN);
01454         SET_FLAG(tmp, FLAG_ALIVE);
01455     }
01456 
01457     /* This can't really hurt - if the object doesn't kill anything,
01458      * these fields just won't be used.
01459      */
01460     set_owner(tmp, op);
01461     set_spell_skill(op, caster, spell_ob, tmp);
01462     tmp->x = x;
01463     tmp->y = y;
01464     tmp->level = caster_level(caster, spell_ob)/2;
01465 
01466     name = tmp->name;
01467     if ((tmp = insert_ob_in_map(tmp, m, op, 0)) == NULL) {
01468         draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01469                              "Something destroys your %s",
01470                              "Something destroys your %s",
01471                              name);
01472         return 0;
01473     }
01474     /* If this is a spellcasting wall, need to insert the spell object */
01475     if (tmp->other_arch && tmp->other_arch->clone.type == SPELL)
01476         insert_ob_in_ob(arch_to_object(tmp->other_arch), tmp);
01477 
01478     /*  This code causes the wall to extend some distance in
01479      * each direction, or until an obstruction is encountered.
01480      * posblocked and negblocked help determine how far the
01481      * created wall can extend, it won't go extend through
01482      * blocked spaces.
01483      */
01484     maxrange = spell_ob->range+SP_level_range_adjust(caster, spell_ob);
01485     posblocked = 0;
01486     negblocked = 0;
01487 
01488     for (i = 1; i <= maxrange; i++) {
01489         int dir2;
01490 
01491         dir2 = (dir < 4) ? (dir+2) : dir-2;
01492 
01493         x = tmp->x+i*freearr_x[dir2];
01494         y = tmp->y+i*freearr_y[dir2];
01495         m = tmp->map;
01496 
01497         if (!(get_map_flags(m, &m, x, y, &x, &y)&(P_OUT_OF_MAP|P_IS_ALIVE))
01498         && ((spell_ob->move_block&GET_MAP_MOVE_BLOCK(m, x, y)) != spell_ob->move_block)
01499         && !posblocked) {
01500             tmp2 = get_object();
01501             copy_object(tmp, tmp2);
01502             tmp2->x = x;
01503             tmp2->y = y;
01504             insert_ob_in_map(tmp2, m, op, 0);
01505             /* If this is a spellcasting wall, need to insert the spell object */
01506             if (tmp2->other_arch && tmp2->other_arch->clone.type == SPELL)
01507                 insert_ob_in_ob(arch_to_object(tmp2->other_arch), tmp2);
01508         } else
01509             posblocked = 1;
01510 
01511         x = tmp->x-i*freearr_x[dir2];
01512         y = tmp->y-i*freearr_y[dir2];
01513         m = tmp->map;
01514 
01515         if (!(get_map_flags(m, &m, x, y, &x, &y)&(P_OUT_OF_MAP|P_IS_ALIVE))
01516         && ((spell_ob->move_block&GET_MAP_MOVE_BLOCK(m, x, y)) != spell_ob->move_block)
01517         && !negblocked) {
01518             tmp2 = get_object();
01519             copy_object(tmp, tmp2);
01520             tmp2->x = x;
01521             tmp2->y = y;
01522             insert_ob_in_map(tmp2, m, op, 0);
01523             if (tmp2->other_arch && tmp2->other_arch->clone.type == SPELL)
01524                 insert_ob_in_ob(arch_to_object(tmp2->other_arch), tmp2);
01525         } else
01526             negblocked = 1;
01527     }
01528 
01529     if (QUERY_FLAG(tmp, FLAG_BLOCKSVIEW))
01530         update_all_los(op->map, op->x, op->y);
01531 
01532     return 1;
01533 }
01534 
01551 int dimension_door(object *op, object *caster, object *spob, int dir) {
01552     uint32 dist, maxdist;
01553     int  mflags;
01554     mapstruct *m;
01555     sint16  sx, sy;
01556 
01557     if (op->type != PLAYER)
01558         return 0;
01559 
01560     if (!dir) {
01561         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
01562                       "In what direction?", NULL);
01563         return 0;
01564     }
01565 
01566     /* Given the new outdoor maps, can't let players dimension door for
01567      * ever, so put limits in.
01568      */
01569     maxdist = spob->range+SP_level_range_adjust(caster, spob);
01570 
01571     if (op->contr->count) {
01572         if (op->contr->count > maxdist) {
01573             draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
01574                           "You can't dimension door that far!", NULL);
01575             return 0;
01576         }
01577 
01578         for (dist = 0; dist < op->contr->count; dist++) {
01579             mflags = get_map_flags(op->map, &m,
01580                                    op->x+freearr_x[dir]*(dist+1),
01581                                    op->y+freearr_y[dir]*(dist+1),
01582                                    &sx, &sy);
01583 
01584             if (mflags&(P_NO_MAGIC|P_OUT_OF_MAP))
01585                 break;
01586 
01587             if ((mflags&P_BLOCKSVIEW)
01588             && OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, sx, sy)))
01589                 break;
01590         }
01591 
01592         if (dist < op->contr->count) {
01593             draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01594                           "Something blocks the magic of the spell.", NULL);
01595             op->contr->count = 0;
01596             return 0;
01597         }
01598         op->contr->count = 0;
01599 
01600         /* Remove code that puts player on random space on maps.  IMO,
01601          * a lot of maps probably have areas the player should not get to,
01602          * but may not be marked as NO_MAGIC (as they may be bounded
01603          * by such squares).  Also, there are probably treasure rooms and
01604          * lots of other maps that protect areas with no magic, but the
01605          * areas themselves don't contain no magic spaces.
01606          */
01607         /* This call here is really just to normalize the coordinates */
01608         mflags = get_map_flags(op->map, &m, op->x+freearr_x[dir]*dist, op->y+freearr_y[dir]*dist,
01609                                &sx, &sy);
01610         if (mflags&P_IS_ALIVE || OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, sx, sy))) {
01611             draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01612                           "You cast your spell, but nothing happens.", NULL);
01613             return 1; /* Maybe the penalty should be more severe... */
01614         }
01615     } else {
01616         /* Player didn't specify a distance, so lets see how far
01617          * we can move the player.  Don't know why this stopped on
01618          * spaces that blocked the players view.
01619          */
01620 
01621         for (dist = 0; dist < maxdist; dist++) {
01622             mflags = get_map_flags(op->map, &m,
01623                                    op->x+freearr_x[dir]*(dist+1),
01624                                    op->y+freearr_y[dir]*(dist+1),
01625                                    &sx, &sy);
01626 
01627             if (mflags&(P_NO_MAGIC|P_OUT_OF_MAP))
01628                 break;
01629 
01630             if ((mflags&P_BLOCKSVIEW)
01631             && OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, sx, sy)))
01632                 break;
01633 
01634         }
01635 
01636         /* If the destination is blocked, keep backing up until we
01637          * find a place for the player.
01638          */
01639         for (; dist > 0; dist--) {
01640             if (get_map_flags(op->map, &m, op->x+freearr_x[dir]*dist, op->y+freearr_y[dir]*dist, &sx, &sy)&(P_OUT_OF_MAP|P_IS_ALIVE))
01641                 continue;
01642 
01643             if (!OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, sx, sy)))
01644                 break;
01645         }
01646         if (!dist) {
01647             draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01648                           "Your spell failed!", NULL);
01649             return 0;
01650         }
01651     }
01652 
01653     /* Actually move the player now */
01654     remove_ob(op);
01655     op->x += freearr_x[dir]*dist;
01656     op->y += freearr_y[dir]*dist;
01657     if ((op = insert_ob_in_map(op, op->map, op, 0)) == NULL)
01658         return 1;
01659 
01660     if (op->type == PLAYER)
01661         map_newmap_cmd(&op->contr->socket);
01662     op->speed_left = -FABS(op->speed)*5; /* Freeze them for a short while */
01663     return 1;
01664 }
01665 
01666 
01679 int cast_heal(object *op, object *caster, object *spell, int dir) {
01680     object *tmp;
01681     archetype *at;
01682     object *poison;
01683     int heal = 0, success = 0;
01684 
01685     tmp = find_target_for_friendly_spell(op, dir);
01686 
01687     if (tmp == NULL)
01688         return 0;
01689 
01690     /* Figure out how many hp this spell might cure.
01691      * could be zero if this spell heals effects, not damage.
01692      */
01693     heal = spell->stats.dam;
01694     if (spell->stats.hp)
01695         heal += random_roll(spell->stats.hp, 6, op, PREFER_HIGH)+spell->stats.hp;
01696 
01697     if (heal) {
01698         if (tmp->stats.hp >= tmp->stats.maxhp) {
01699             draw_ext_info(NDI_UNIQUE, 0, tmp, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01700                           "You are already fully healed.", NULL);
01701         } else {
01702             /* See how many points we actually heal.  Instead of messages
01703              * based on type of spell, we instead do messages based
01704              * on amount of damage healed.
01705              */
01706             if (heal > (tmp->stats.maxhp-tmp->stats.hp))
01707                 heal = tmp->stats.maxhp-tmp->stats.hp;
01708             tmp->stats.hp += heal;
01709 
01710             if (tmp->stats.hp >= tmp->stats.maxhp) {
01711                 draw_ext_info(NDI_UNIQUE, 0, tmp, MSG_TYPE_SPELL, MSG_TYPE_SPELL_HEAL,
01712                               "You feel just fine!", NULL);
01713             } else if (heal > 50) {
01714                 draw_ext_info(NDI_UNIQUE, 0, tmp, MSG_TYPE_SPELL, MSG_TYPE_SPELL_HEAL,
01715                               "Your wounds close!", NULL);
01716             } else if (heal > 25) {
01717                 draw_ext_info(NDI_UNIQUE, 0, tmp, MSG_TYPE_SPELL, MSG_TYPE_SPELL_HEAL,
01718                               "Your wounds mostly close.", NULL);
01719             } else if (heal > 10) {
01720                 draw_ext_info(NDI_UNIQUE, 0, tmp, MSG_TYPE_SPELL, MSG_TYPE_SPELL_HEAL,
01721                               "Your wounds start to fade.", NULL);
01722             } else {
01723                 draw_ext_info(NDI_UNIQUE, 0, tmp, MSG_TYPE_SPELL, MSG_TYPE_SPELL_HEAL,
01724                               "Your wounds start to close.", NULL);
01725             }
01726             success = 1;
01727         }
01728     }
01729     if (spell->attacktype&AT_DISEASE)
01730         if (cure_disease(tmp, op))
01731             success = 1;
01732 
01733     if (spell->attacktype&AT_POISON) {
01734         at = find_archetype("poisoning");
01735         poison = present_arch_in_ob(at, tmp);
01736         if (poison) {
01737             success = 1;
01738             draw_ext_info(NDI_UNIQUE, 0, tmp, MSG_TYPE_SPELL, MSG_TYPE_SPELL_HEAL,
01739                           "Your body feels cleansed", NULL);
01740             poison->stats.food = 1;
01741         }
01742     }
01743     if (spell->attacktype&AT_CONFUSION) {
01744         poison = present_in_ob_by_name(FORCE, "confusion", tmp);
01745         if (poison) {
01746             success = 1;
01747             draw_ext_info(NDI_UNIQUE, 0, tmp, MSG_TYPE_SPELL, MSG_TYPE_SPELL_HEAL,
01748                           "Your mind feels clearer", NULL);
01749             poison->duration = 1;
01750         }
01751     }
01752     if (spell->attacktype&AT_BLIND) {
01753         at = find_archetype("blindness");
01754         poison = present_arch_in_ob(at, tmp);
01755         if (poison) {
01756             success = 1;
01757             draw_ext_info(NDI_UNIQUE, 0, tmp, MSG_TYPE_SPELL, MSG_TYPE_SPELL_HEAL,
01758                           "Your vision begins to return.", NULL);
01759             poison->stats.food = 1;
01760         }
01761     }
01762     if (spell->last_sp && tmp->stats.sp < tmp->stats.maxsp) {
01763         tmp->stats.sp += spell->last_sp;
01764         if (tmp->stats.sp > tmp->stats.maxsp)
01765             tmp->stats.sp = tmp->stats.maxsp;
01766         success = 1;
01767         draw_ext_info(NDI_UNIQUE, 0, tmp, MSG_TYPE_SPELL, MSG_TYPE_SPELL_HEAL,
01768                       "Magical energies surge through your body!", NULL);
01769     }
01770     if (spell->last_grace && tmp->stats.grace < tmp->stats.maxgrace) {
01771         tmp->stats.grace += spell->last_grace;
01772         if (tmp->stats.grace > tmp->stats.maxgrace)
01773             tmp->stats.grace = tmp->stats.maxgrace;
01774         success = 1;
01775         draw_ext_info(NDI_UNIQUE, 0, tmp, MSG_TYPE_SPELL, MSG_TYPE_SPELL_HEAL,
01776                       "You feel redeemed with you god!", NULL);
01777     }
01778     if (spell->stats.food && tmp->stats.food < 999) {
01779         tmp->stats.food += spell->stats.food;
01780         if (tmp->stats.food > 999)
01781             tmp->stats.food = 999;
01782         success = 1;
01783         /* We could do something a bit better like the messages for healing above */
01784         draw_ext_info(NDI_UNIQUE, 0, tmp, MSG_TYPE_SPELL, MSG_TYPE_SPELL_HEAL,
01785                       "You feel your belly fill with food", NULL);
01786     }
01787     return success;
01788 }
01789 
01790 
01796 static const char *const no_gain_msgs[NUM_STATS] = {
01797     "You grow no stronger.",
01798     "You grow no more agile.",
01799     "You don't feel any healthier.",
01800     "no wis",
01801     "You are no easier to look at.",
01802     "no int",
01803     "no pow"
01804 };
01805 
01825 int cast_change_ability(object *op, object *caster, object *spell_ob, int dir, int silent) {
01826     object *tmp, *tmp2 = NULL;
01827     object *force = NULL;
01828     int i;
01829 
01830     /* if dir = 99 op defaults to tmp, eat_special_food() requires this. */
01831     if (dir != 0) {
01832         tmp = find_target_for_friendly_spell(op, dir);
01833     } else {
01834         tmp = op;
01835     }
01836 
01837     if (tmp == NULL)
01838         return 0;
01839 
01840     /* If we've already got a force of this type, don't add a new one. */
01841     for (tmp2 = tmp->inv; tmp2 != NULL; tmp2 = tmp2->below) {
01842         if (tmp2->type == FORCE && tmp2->subtype == FORCE_CHANGE_ABILITY)  {
01843             if (tmp2->name == spell_ob->name) {
01844                 force = tmp2;    /* the old effect will be "refreshed" */
01845                 break;
01846             } else if (spell_ob->race && spell_ob->race == tmp2->name) {
01847                 if (!silent)
01848                     draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
01849                                          "You can not cast %s while %s is in effect",
01850                                          "You can not cast %s while %s is in effect",
01851                                          spell_ob->name, tmp2->name_pl);
01852                 return 0;
01853             }
01854         }
01855     }
01856     if (force == NULL) {
01857         force = create_archetype(FORCE_NAME);
01858         force->subtype = FORCE_CHANGE_ABILITY;
01859         free_string(force->name);
01860         if (spell_ob->race)
01861             force->name = add_refcount(spell_ob->race);
01862         else
01863             force->name = add_refcount(spell_ob->name);
01864         free_string(force->name_pl);
01865         force->name_pl = add_refcount(spell_ob->name);
01866     } else {
01867         int duration;
01868 
01869         duration = spell_ob->duration+SP_level_duration_adjust(caster, spell_ob)*50;
01870         if (duration > force->duration) {
01871             force->duration = duration;
01872             draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_SUCCESS,
01873                           "You recast the spell while in effect.", NULL);
01874         } else {
01875             draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01876                           "Recasting the spell had no effect.", NULL);
01877         }
01878         return 1;
01879     }
01880     force->duration = spell_ob->duration+SP_level_duration_adjust(caster, spell_ob)*50;
01881     if (op->type == PLAYER)
01882         store_spell_expiry(force);
01883     force->speed = 1.0;
01884     force->speed_left = -1.0;
01885     SET_FLAG(force, FLAG_APPLIED);
01886 
01887     /* Now start processing the effects.  First, protections */
01888     for (i = 0; i < NROFATTACKS; i++) {
01889         if (spell_ob->resist[i]) {
01890             force->resist[i] = spell_ob->resist[i]+SP_level_dam_adjust(caster, spell_ob);
01891             if (force->resist[i] > 100)
01892                 force->resist[i] = 100;
01893         }
01894     }
01895     if (spell_ob->stats.hp)
01896         force->stats.hp = spell_ob->stats.hp+SP_level_dam_adjust(caster, spell_ob);
01897 
01898     if (tmp->type == PLAYER) {
01899         /* Stat adjustment spells */
01900         for (i = 0; i < NUM_STATS; i++) {
01901             sint8 stat = get_attr_value(&spell_ob->stats, i), k, sm;
01902 
01903             if (stat) {
01904                 sm = 0;
01905                 for (k = 0; k < stat; k++)
01906                     sm += rndm(1, 3);
01907 
01908                 if ((get_attr_value(&tmp->stats, i)+sm) > (15+5*stat)) {
01909                     sm = (15+5*stat)-get_attr_value(&tmp->stats, i);
01910                     if (sm < 0)
01911                         sm = 0;
01912                 }
01913                 set_attr_value(&force->stats, i, sm);
01914                 if (!sm)
01915                     draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01916                                   no_gain_msgs[i], no_gain_msgs[i]);
01917             }
01918         }
01919     }
01920 
01921     force->move_type = spell_ob->move_type;
01922 
01923     if (QUERY_FLAG(spell_ob, FLAG_SEE_IN_DARK))
01924         SET_FLAG(force, FLAG_SEE_IN_DARK);
01925 
01926     if (QUERY_FLAG(spell_ob, FLAG_XRAYS))
01927         SET_FLAG(force, FLAG_XRAYS);
01928 
01929     /* Haste/bonus speed */
01930     if (spell_ob->stats.exp) {
01931         if (op->speed > 0.5)
01932             force->stats.exp = (float)spell_ob->stats.exp/(op->speed+0.5);
01933         else
01934             force->stats.exp = spell_ob->stats.exp;
01935     }
01936 
01937     force->stats.wc = spell_ob->stats.wc;
01938     force->stats.ac = spell_ob->stats.ac;
01939     force->attacktype = spell_ob->attacktype;
01940 
01941     SET_FLAG(tmp, FLAG_NO_FIX_PLAYER); /* we don't want insert_ob_in_ob to call fix_object. */
01942     insert_ob_in_ob(force, tmp);
01943     CLEAR_FLAG(tmp, FLAG_NO_FIX_PLAYER);
01944     change_abil(tmp, force); /* Display any relevant messages, and call fix_object to update the player */
01945 
01946     return 1;
01947 }
01948 
01965 int cast_bless(object *op, object *caster, object *spell_ob, int dir) {
01966     int i;
01967     const object *god = find_god(determine_god(op));
01968     object *tmp2, *force = NULL, *tmp;
01969 
01970     /* if dir = 99 op defaults to tmp, eat_special_food() requires this. */
01971     if (dir != 0) {
01972         tmp = find_target_for_friendly_spell(op, dir);
01973     } else {
01974         tmp = op;
01975     }
01976 
01977     /* If we've already got a force of this type, don't add a new one. */
01978     for (tmp2 = tmp->inv; tmp2 != NULL; tmp2 = tmp2->below) {
01979         if (tmp2->type == FORCE && tmp2->subtype == FORCE_CHANGE_ABILITY)  {
01980             if (tmp2->name == spell_ob->name) {
01981                 force = tmp2;    /* the old effect will be "refreshed" */
01982                 break;
01983             } else if (spell_ob->race && spell_ob->race == tmp2->name) {
01984                 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
01985                                      "You can not cast %s while %s is in effect",
01986                                      "You can not cast %s while %s is in effect",
01987                                      spell_ob->name, tmp2->name_pl);
01988                 return 0;
01989             }
01990         }
01991     }
01992     if (force == NULL) {
01993         force = create_archetype(FORCE_NAME);
01994         force->subtype = FORCE_CHANGE_ABILITY;
01995         free_string(force->name);
01996         if (spell_ob->race)
01997             force->name = add_refcount(spell_ob->race);
01998         else
01999             force->name = add_refcount(spell_ob->name);
02000         free_string(force->name_pl);
02001         force->name_pl = add_refcount(spell_ob->name);
02002     } else {
02003         int duration;
02004 
02005         duration = spell_ob->duration+SP_level_duration_adjust(caster, spell_ob)*50;
02006         if (duration > force->duration) {
02007             force->duration = duration;
02008             draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_SUCCESS,
02009                           "You recast the spell while in effect.", NULL);
02010         } else {
02011             draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
02012                           "Recasting the spell had no effect.", NULL);
02013         }
02014         return 0;
02015     }
02016     force->duration = spell_ob->duration+SP_level_duration_adjust(caster, spell_ob)*50;
02017     force->speed = 1.0;
02018     force->speed_left = -1.0;
02019     SET_FLAG(force, FLAG_APPLIED);
02020 
02021     if (!god) {
02022         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
02023                       "Your blessing seems empty.", NULL);
02024     } else {
02025         /* Only give out good benefits, and put a max on it */
02026         for (i = 0; i < NROFATTACKS; i++) {
02027             if (god->resist[i] > 0) {
02028                 force->resist[i] = MIN(god->resist[i], spell_ob->resist[ATNR_GODPOWER]);
02029             }
02030         }
02031         force->path_attuned |= god->path_attuned;
02032         if (spell_ob->attacktype) {
02033             force->attacktype |= god->attacktype|AT_PHYSICAL;
02034             if (god->slaying)
02035                 force->slaying = add_string(god->slaying);
02036         }
02037         if (tmp != op) {
02038             draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_SUCCESS,
02039                                  "You bless %s.",
02040                                  "You bless %s.",
02041                                  tmp->name);
02042             draw_ext_info_format(NDI_UNIQUE, 0, tmp, MSG_TYPE_SPELL, MSG_TYPE_SPELL_TARGET,
02043                                  "%s blessed you.",
02044                                  "%s blessed you.",
02045                                  op->name);
02046         } else {
02047             draw_ext_info_format(NDI_UNIQUE, 0, tmp, MSG_TYPE_SPELL, MSG_TYPE_SPELL_TARGET,
02048                                  "You are blessed by %s!",
02049                                  "You are blessed by %s!",
02050                                  god->name);
02051         }
02052     }
02053     force->stats.wc = spell_ob->stats.wc;
02054     force->stats.ac = spell_ob->stats.ac;
02055 
02056     change_abil(tmp, force); /* Mostly to display any messages */
02057     insert_ob_in_ob(force, tmp);
02058     fix_object(tmp);
02059     return 1;
02060 }
02061 
02062 
02063 
02064 /*
02065  * Alchemy code by Mark Wedel
02066  *
02067  * This code adds a new spell, called alchemy.  Alchemy will turn
02068  * objects to gold nuggets, the value of the gold nuggets being
02069  * from 5% to 40% of that of the item itself depending on casting level.
02070  * It uses the value of the object before charisma adjustments, because
02071  * the nuggets themselves will be will be adjusted by charisma when sold.
02072  *
02073  * Large nuggets are worth 25 gp each (base).  You will always get
02074  * the maximum number of large nuggets you could get.
02075  * Small nuggets are worth 1 gp each (base).  You will get from 0
02076  * to the max amount of small nuggets as you could get.
02077  *
02078  * For example, if an item is worth 110 gold, you will get
02079  * 4 large nuggets, and from 0-10 small nuggets.
02080  *
02081  * There is also a chance (1:30) that you will get nothing at all
02082  * for the object.  There is also a maximum weight that will be
02083  * alchemied.
02084  */
02085 
02086 /* I didn't feel like passing these as arguements to the
02087  * two functions that need them.  Real values are put in them
02088  * when the spell is cast, and these are freed when the spell
02089  * is finished.
02090  */
02091 static object *small, *large; 
02093 static uint64 small_value, large_value; 
02109 static void alchemy_object(float value_adj, object *obj, int *small_nuggets, int *large_nuggets, int *weight) {
02110     uint64 value = query_cost(obj, NULL, F_TRUE);
02111 
02112     /* Multiply the value of the object by value_adj, which should range
02113      * from 0.05 to 0.40. Set value to 0 instead if unpaid.
02114      */
02115     if (QUERY_FLAG(obj, FLAG_UNPAID))
02116         value = 0;
02117     else
02118         value *= value_adj;
02119 
02120 
02121     /* Give half of what value_adj says when we alchemy money (This should
02122      * hopefully make it so that it isn't worth it to alchemy money, sell
02123      * the nuggets, alchemy the gold from that, etc.
02124      */
02125     if (value && (obj->type == MONEY || obj->type == GEM))
02126         value /= 2;
02127 
02128     if ((obj->value > 0) && rndm(0, 29)) {
02129         int count;
02130 
02131         count = value/large_value;
02132         *large_nuggets += count;
02133         value -= (uint64)count*large_value;
02134         count = value/small_value;
02135         *small_nuggets += count;
02136     }
02137 
02138     /* Turn 25 small nuggets into 1 large nugget.  If the value
02139      * of large nuggets is not evenly divisable by the small nugget
02140      * value, take off an extra small_nugget (Assuming small_nuggets!=0)
02141      */
02142     if (*small_nuggets*small_value >= large_value) {
02143         (*large_nuggets)++;
02144         *small_nuggets -= large_value/small_value;
02145         if (*small_nuggets && large_value%small_value)
02146             (*small_nuggets)--;
02147     }
02148     weight += obj->weight;
02149     remove_ob(obj);
02150     free_object(obj);
02151 }
02152 
02166 static void place_alchemy_objects(object *op, mapstruct *m, int small_nuggets, int large_nuggets, int x, int y) {
02167     object *tmp;
02168     int flag = 0;
02169 
02170     /* Put any nuggets below the player, but we can only pass this
02171      * flag if we are on the same space as the player
02172      */
02173     if (x == op->x && y == op->y && op->map == m)
02174         flag = INS_BELOW_ORIGINATOR;
02175 
02176     if (small_nuggets) {
02177         tmp = get_object();
02178         copy_object(small, tmp);
02179         tmp-> nrof = small_nuggets;
02180         tmp->x = x;
02181         tmp->y = y;
02182         insert_ob_in_map(tmp, m, op, flag);
02183     }
02184     if (large_nuggets) {
02185         tmp = get_object();
02186         copy_object(large, tmp);
02187         tmp-> nrof = large_nuggets;
02188         tmp->x = x;
02189         tmp->y = y;
02190         insert_ob_in_map(tmp, m, op, flag);
02191     }
02192 }
02193 
02208 int alchemy(object *op, object *caster, object *spell_ob) {
02209     int x, y, weight = 0, weight_max, large_nuggets, small_nuggets, mflags;
02210     sint16 nx, ny;
02211     float value_adj;
02212     object *next, *tmp;
02213     mapstruct *mp;
02214 
02215     if (op->type != PLAYER)
02216         return 0;
02217 
02218     /* Put a maximum weight of items that can be alchemied.  Limits the power
02219      * some, and also prevents people from alcheming every table/chair/clock
02220      * in sight
02221      */
02222     weight_max = spell_ob->duration+SP_level_duration_adjust(caster, spell_ob);
02223     weight_max *= 1000;
02224     small = create_archetype("smallnugget"),
02225     large = create_archetype("largenugget");
02226     small_value = query_cost(small, NULL, F_TRUE);
02227     large_value = query_cost(large, NULL, F_TRUE);
02228 
02229     /* Set value_adj to be a multiplier for how much of the original value
02230      * will be in the nuggets. Starts at 0.05, increasing by 0.01 per casting
02231      * level, maxing out at 0.40.
02232      */
02233     value_adj = (SP_level_dam_adjust(caster, spell_ob)/100.00)+0.05;
02234 
02235     if (value_adj > 0.40)
02236         value_adj = 0.40;
02237 
02238     for (y = op->y-1; y <= op->y+1; y++) {
02239         for (x = op->x-1; x <= op->x+1; x++) {
02240             nx = x;
02241             ny = y;
02242 
02243             mp = op->map;
02244 
02245             mflags = get_map_flags(mp, &mp, nx, ny, &nx, &ny);
02246 
02247             if (mflags&(P_OUT_OF_MAP|P_NO_MAGIC))
02248                 continue;
02249 
02250             /* Treat alchemy a little differently - most spell effects
02251              * use fly as the movement type - for alchemy, consider it
02252              * ground level effect.
02253              */
02254             if (GET_MAP_MOVE_BLOCK(mp, nx, ny)&MOVE_WALK)
02255                 continue;
02256 
02257             small_nuggets = 0;
02258             large_nuggets = 0;
02259 
02260             for (tmp = GET_MAP_OB(mp, nx, ny); tmp != NULL; tmp = next) {
02261                 next = tmp->above;
02262                 if (tmp->weight > 0 && !QUERY_FLAG(tmp, FLAG_NO_PICK)
02263                 && !QUERY_FLAG(tmp, FLAG_ALIVE)
02264                 && !QUERY_FLAG(tmp, FLAG_IS_CAULDRON)) {
02265                     if (tmp->inv) {
02266                         object *next1, *tmp1;
02267                         for (tmp1 = tmp->inv; tmp1 != NULL; tmp1 = next1) {
02268                             next1 = tmp1->below;
02269                             if (tmp1->weight > 0 && !QUERY_FLAG(tmp1, FLAG_NO_PICK)
02270                             && !QUERY_FLAG(tmp1, FLAG_ALIVE)
02271                             && !QUERY_FLAG(tmp1, FLAG_IS_CAULDRON))
02272                                 alchemy_object(value_adj, tmp1, &small_nuggets, &large_nuggets, &weight);
02273                         }
02274                     }
02275                     alchemy_object(value_adj, tmp, &small_nuggets, &large_nuggets, &weight);
02276 
02277                     if (weight > weight_max) {
02278                         place_alchemy_objects(op, mp, small_nuggets, large_nuggets, nx, ny);
02279                         free_object(large);
02280                         free_object(small);
02281                         return 1;
02282                     }
02283                 } /* is alchemable object */
02284             } /* process all objects on this space */
02285 
02286             /* Insert all the nuggets at one time.  This probably saves time, but
02287              * it also prevents us from alcheming nuggets that were just created
02288              * with this spell.
02289              */
02290             place_alchemy_objects(op, mp, small_nuggets, large_nuggets, nx, ny);
02291         }
02292     }
02293     free_object(large);
02294     free_object(small);
02295     /* reset this so that if player standing on a big pile of stuff,
02296      * it is redrawn properly.
02297      */
02298     op->contr->socket.look_position = 0;
02299     return 1;
02300 }
02301 
02302 
02317 int remove_curse(object *op, object *caster, object *spell) {
02318     object *tmp;
02319     int success = 0, was_one = 0;
02320 
02321     for (tmp = op->inv; tmp; tmp = tmp->below)
02322         if (QUERY_FLAG(tmp, FLAG_APPLIED)
02323         && ((QUERY_FLAG(tmp, FLAG_CURSED) && QUERY_FLAG(spell, FLAG_CURSED))
02324             || (QUERY_FLAG(tmp, FLAG_DAMNED) && QUERY_FLAG(spell, FLAG_DAMNED)))) {
02325             was_one++;
02326             if (tmp->level <= caster_level(caster, spell)) {
02327                 success++;
02328                 if (QUERY_FLAG(spell, FLAG_DAMNED))
02329                     CLEAR_FLAG(tmp, FLAG_DAMNED);
02330 
02331                 CLEAR_FLAG(tmp, FLAG_CURSED);
02332                 CLEAR_FLAG(tmp, FLAG_KNOWN_CURSED);
02333                 tmp->value = 0; /* Still can't sell it */
02334                 if (op->type == PLAYER)
02335                     esrv_update_item(UPD_FLAGS, op, tmp);
02336             }
02337         }
02338 
02339     if (op->type == PLAYER) {
02340         if (success) {
02341             draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_SUCCESS,
02342                           "You feel like some of your items are looser now.", NULL);
02343         } else {
02344             if (was_one)
02345                 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
02346                               "You failed to remove the curse.", NULL);
02347             else
02348                 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
02349                               "You are not using any cursed items.", NULL);
02350         }
02351     }
02352     return success;
02353 }
02354 
02367 int cast_item_curse_or_curse(object *op, object *caster, object *spell_ob) {
02368     object *marked = find_marked_object(op);
02369     char name[HUGE_BUF];
02370 
02371     if (!marked) {
02372         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
02373                       "You need to mark an item first!", NULL);
02374         return 0;
02375     }
02376 
02377     if ((QUERY_FLAG(marked, FLAG_CURSED) && QUERY_FLAG(spell_ob, FLAG_CURSED))
02378         || (QUERY_FLAG(marked, FLAG_BLESSED) && QUERY_FLAG(spell_ob, FLAG_BLESSED))) {
02379         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
02380                       "The spell has no effect", NULL);
02381         return 0;
02382     }
02383 
02384     query_short_name(marked, name, HUGE_BUF);
02385     if (QUERY_FLAG(spell_ob, FLAG_CURSED)) {
02386         draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_SUCCESS,
02387                              "Your %s emits a dark light for a few seconds.", "Your %s emits a dark light for a few seconds.", name);
02388         SET_FLAG(marked, FLAG_CURSED);
02389         CLEAR_FLAG(marked, FLAG_KNOWN_CURSED);
02390         CLEAR_FLAG(marked, FLAG_IDENTIFIED);
02391         esrv_update_item(UPD_FLAGS, op, marked);
02392         return 1;
02393 
02394     }
02395 
02396     draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_SUCCESS,
02397                          "Your %s glows blue for a few seconds.", "Your %s glows blue for a few seconds.", name);
02398     SET_FLAG(marked, FLAG_BLESSED);
02399     SET_FLAG(marked, FLAG_KNOWN_BLESSED);
02400     SET_FLAG(marked, FLAG_STARTEQUIP);
02401     esrv_update_item(UPD_FLAGS, op, marked);
02402     return 1;
02403 }
02404 
02419 int cast_identify(object *op, object *caster, object *spell) {
02420     object *tmp;
02421     int success = 0, num_ident;
02422     char desc[MAX_BUF];
02423 
02424     num_ident = spell->stats.dam+SP_level_dam_adjust(caster, spell);
02425 
02426     if (num_ident < 1)
02427         num_ident = 1;
02428 
02429     for (tmp = op->inv; tmp; tmp = tmp->below) {
02430         if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED) && !tmp->invisible &&  need_identify(tmp)) {
02431             identify(tmp);
02432             if (op->type == PLAYER) {
02433                 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_ITEM, MSG_TYPE_ITEM_INFO,
02434                                      "You have %s.",
02435                                      "You have %s.",
02436                                      ob_describe(tmp, op, desc, sizeof(desc)));
02437                 if (tmp->msg) {
02438                     draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_ITEM, MSG_TYPE_ITEM_INFO,
02439                                          "The item has a story:\n%s",
02440                                          "The item has a story:\n%s",
02441                                          tmp->msg);
02442                 }
02443             }
02444             num_ident--;
02445             success = 1;
02446             if (!num_ident)
02447                 break;
02448         }
02449     }
02450     /* If all the power of the spell has been used up, don't go and identify
02451      * stuff on the floor.  Only identify stuff on the floor if the spell
02452      * was not fully used.
02453      */
02454     if (num_ident) {
02455         for (tmp = GET_MAP_OB(op->map, op->x, op->y); tmp != NULL; tmp = tmp->above)
02456             if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED)
02457             && !tmp->invisible
02458             && need_identify(tmp)) {
02459                 identify(tmp);
02460                 if (op->type == PLAYER) {
02461                     draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_ITEM, MSG_TYPE_ITEM_INFO,
02462                                          "On the ground is %s.",
02463                                          "On the ground is %s.",
02464                                          ob_describe(tmp, op, desc, sizeof(desc)));
02465                     if (tmp->msg) {
02466                         draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_ITEM, MSG_TYPE_ITEM_INFO,
02467                                              "The item has a story:\n%s",
02468                                              "The item has a story:\n%s",
02469                                              tmp->msg);
02470                     }
02471                     esrv_update_item(UPD_FLAGS|UPD_NAME, op, tmp);
02472                 }
02473                 num_ident--;
02474                 success = 1;
02475                 if (!num_ident)
02476                     break;
02477             }
02478     }
02479     if (!success)
02480         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
02481                       "You can't reach anything unidentified.", NULL);
02482     else {
02483         spell_effect(spell, op->x, op->y, op->map, op);
02484     }
02485     return success;
02486 }
02487 
02500 int cast_detection(object *op, object *caster, object *spell) {
02501     object *tmp, *last, *detect;
02502     const object *god;
02503     int done_one, range, mflags, floor, level;
02504     sint16 x, y, nx, ny;
02505     mapstruct *m;
02506 
02507     /* We precompute some values here so that we don't have to keep
02508      * doing it over and over again.
02509      */
02510     god = find_god(determine_god(op));
02511     level = caster_level(caster, spell);
02512     range = spell->range+SP_level_range_adjust(caster, spell);
02513 
02514     for (x = op->x-range; x <= op->x+range; x++)
02515         for (y = op->y-range; y <= op->y+range; y++) {
02516 
02517             m = op->map;
02518             mflags = get_map_flags(m, &m, x, y, &nx, &ny);
02519             if (mflags&P_OUT_OF_MAP)
02520                 continue;
02521 
02522             /* For most of the detections, we only detect objects above the
02523              * floor.  But this is not true for show invisible.
02524              * Basically, we just go and find the top object and work
02525              * down - that is easier than working up.
02526              */
02527 
02528             for (last = NULL, tmp = GET_MAP_OB(m, nx, ny); tmp; tmp = tmp->above)
02529                 last = tmp;
02530             /* Shouldn't happen, but if there are no objects on a space, this
02531              * would happen.
02532              */
02533             if (!last)
02534                 continue;
02535 
02536             done_one = 0;
02537             floor = 0;
02538             detect = NULL;
02539             for (tmp = last; tmp; tmp = tmp->below) {
02540                 /* show invisible */
02541                 if (QUERY_FLAG(spell, FLAG_MAKE_INVIS)
02542                     /* Might there be other objects that we can make visibile? */
02543                 && (tmp->invisible && (QUERY_FLAG(tmp, FLAG_MONSTER) ||
02544                                         (tmp->type == PLAYER && !QUERY_FLAG(tmp, FLAG_WIZ)) ||
02545                                         tmp->type == CF_HANDLE ||
02546                                         tmp->type == TRAPDOOR || tmp->type == EXIT || tmp->type == HOLE ||
02547                                         tmp->type == BUTTON || tmp->type == TELEPORTER ||
02548                                         tmp->type == GATE || tmp->type == LOCKED_DOOR ||
02549                                         tmp->type == WEAPON || tmp->type == ALTAR || tmp->type == SIGN ||
02550                                         tmp->type == TRIGGER_PEDESTAL || tmp->type == SPECIAL_KEY ||
02551                                         tmp->type == TREASURE || tmp->type == BOOK ||
02552                                         tmp->type == HOLY_ALTAR))) {
02553                     if (random_roll(0, level-1, op, PREFER_HIGH) > tmp->level) {
02554                         tmp->invisible = 0;
02555                         done_one = 1;
02556                     }
02557                 }
02558                 if (QUERY_FLAG(tmp, FLAG_IS_FLOOR))
02559                     floor = 1;
02560 
02561                 /* All detections below this point don't descend beneath the floor,
02562                  * so just continue on.  We could be clever and look at the type of
02563                  * detection to completely break out if we don't care about objects beneath
02564                  * the floor, but once we get to the floor, not likely a very big issue anyways.
02565                  */
02566                 if (floor)
02567                     continue;
02568 
02569                 /* I had thought about making detect magic and detect curse
02570                  * show the flash the magic item like it does for detect monster.
02571                  * however, if the object is within sight, this would then make it
02572                  * difficult to see what object is magical/cursed, so the
02573                  * effect wouldn't be as apparant.
02574                  */
02575 
02576                 /* detect magic */
02577                 if (QUERY_FLAG(spell, FLAG_KNOWN_MAGICAL)
02578                 && !QUERY_FLAG(tmp, FLAG_KNOWN_MAGICAL)
02579                 && !QUERY_FLAG(tmp, FLAG_IDENTIFIED)
02580                 && is_magical(tmp)) {
02581                     SET_FLAG(tmp, FLAG_KNOWN_MAGICAL);
02582                     /* make runes more visibile */
02583                     if (tmp->type == RUNE && tmp->attacktype&AT_MAGIC)
02584                         tmp->stats.Cha /= 4;
02585                     done_one = 1;
02586                 }
02587                 /* detect monster */
02588                 if (QUERY_FLAG(spell, FLAG_MONSTER)
02589                 && (QUERY_FLAG(tmp, FLAG_MONSTER) || (tmp->type == PLAYER && !QUERY_FLAG(tmp, FLAG_WIZ)))) {
02590                     done_one = 2;
02591                     if (!detect)
02592                         detect = tmp;
02593                 }
02594                 /* Basically, if race is set in the spell, then the creatures race must
02595                  * match that.  if the spell race is set to GOD, then the gods opposing
02596                  * race must match.
02597                  */
02598                 if (spell->race
02599                 && QUERY_FLAG(tmp, FLAG_MONSTER)
02600                 && tmp->race
02601                 && ((!strcmp(spell->race, "GOD") && god && god->slaying && strstr(god->slaying, tmp->race)) || (strstr(spell->race, tmp->race)))) {
02602                     done_one = 2;
02603                     if (!detect)
02604                         detect = tmp;
02605                 }
02606                 if (QUERY_FLAG(spell, FLAG_KNOWN_CURSED)
02607                 && !QUERY_FLAG(tmp, FLAG_KNOWN_CURSED)
02608                 && (QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED))) {
02609                     SET_FLAG(tmp, FLAG_KNOWN_CURSED);
02610                     done_one = 1;
02611                 }
02612             } /* for stack of objects on this space */
02613 
02614             /* Code here puts an effect of the spell on the space, so you can see
02615              * where the magic is.
02616              */
02617             if (done_one) {
02618                 object *detect_ob = arch_to_object(spell->other_arch);
02619 
02620                 detect_ob->x = nx;
02621                 detect_ob->y = ny;
02622                 /* if this is set, we want to copy the face */
02623                 if (done_one == 2 && detect) {
02624                     detect_ob->face = detect->face;
02625                     detect_ob->animation_id = detect->animation_id;
02626                     detect_ob->anim_speed = detect->anim_speed;
02627                     detect_ob->last_anim = 0;
02628                     /* by default, the detect_ob is already animated */
02629                     if (!QUERY_FLAG(detect, FLAG_ANIMATE))
02630                         CLEAR_FLAG(detect_ob, FLAG_ANIMATE);
02631                 }
02632                 insert_ob_in_map(detect_ob, m, op, 0);
02633             }
02634         } /* for processing the surrounding spaces */
02635 
02636 
02637     /* Now process objects in the players inventory if detect curse or magic */
02638     if (QUERY_FLAG(spell, FLAG_KNOWN_CURSED) || QUERY_FLAG(spell, FLAG_KNOWN_MAGICAL)) {
02639         done_one = 0;
02640         for (tmp = op->inv; tmp; tmp = tmp->below) {
02641             if (!tmp->invisible && !QUERY_FLAG(tmp, FLAG_IDENTIFIED)) {
02642                 if (QUERY_FLAG(spell, FLAG_KNOWN_MAGICAL)
02643                 && is_magical(tmp)
02644                 && !QUERY_FLAG(tmp, FLAG_KNOWN_MAGICAL)) {
02645                     SET_FLAG(tmp, FLAG_KNOWN_MAGICAL);
02646                     if (op->type == PLAYER)
02647                         esrv_send_item(op, tmp);
02648                 }
02649                 if (QUERY_FLAG(spell, FLAG_KNOWN_CURSED)
02650                 && !QUERY_FLAG(tmp, FLAG_KNOWN_CURSED)
02651                 && (QUERY_FLAG(tmp, FLAG_CURSED) || QUERY_FLAG(tmp, FLAG_DAMNED))) {
02652                     SET_FLAG(tmp, FLAG_KNOWN_CURSED);
02653                     if (op->type == PLAYER)
02654                         esrv_send_item(op, tmp);
02655                 }
02656             } /* if item is not identified */
02657         } /* for the players inventory */
02658     } /* if detect magic/curse and object is a player */
02659     return 1;
02660 }
02661 
02669 static void charge_mana_effect(object *victim, int caster_level) {
02670     /* Prevent explosions for objects without mana. Without this check, doors
02671      * will explode, too.
02672      */
02673     if (victim->stats.maxsp <= 0)
02674         return;
02675 
02676     draw_ext_info(NDI_UNIQUE, 0, victim, MSG_TYPE_SPELL, MSG_TYPE_SPELL_TARGET,
02677                   "You feel energy course through you.", NULL);
02678 
02679     if (victim->stats.sp >= victim->stats.maxsp*2) {
02680         object *tmp;
02681 
02682         draw_ext_info(NDI_UNIQUE, 0, victim, MSG_TYPE_VICTIM, MSG_TYPE_VICTIM_SPELL,
02683                       "Your head explodes!", NULL);
02684 
02685         /* Explodes a fireball centered at player */
02686         tmp = create_archetype(EXPLODING_FIREBALL);
02687         tmp->dam_modifier = random_roll(1, caster_level, victim, PREFER_LOW)/5+1;
02688         tmp->stats.maxhp = random_roll(1, caster_level, victim, PREFER_LOW)/10+2;
02689         tmp->x = victim->x;
02690         tmp->y = victim->y;
02691         insert_ob_in_map(tmp, victim->map, NULL, 0);
02692         victim->stats.sp = 2*victim->stats.maxsp;
02693     } else if (victim->stats.sp >= victim->stats.maxsp*1.88) {
02694         draw_ext_info(NDI_UNIQUE, NDI_ORANGE, victim, MSG_TYPE_SPELL, MSG_TYPE_SPELL_TARGET,
02695                       "You feel like your head is going to explode.", NULL);
02696     } else if (victim->stats.sp >= victim->stats.maxsp*1.66) {
02697         draw_ext_info(NDI_UNIQUE, 0, victim, MSG_TYPE_SPELL, MSG_TYPE_SPELL_TARGET,
02698                       "You get a splitting headache!", NULL);
02699     } else if (victim->stats.sp >= victim->stats.maxsp*1.5) {
02700         draw_ext_info(NDI_UNIQUE, 0, victim, MSG_TYPE_SPELL, MSG_TYPE_SPELL_TARGET,
02701                       "Chaos fills your world.", NULL);
02702         confuse_living(victim, victim, 99);
02703     } else if (victim->stats.sp >= victim->stats.maxsp*1.25) {
02704         draw_ext_info(NDI_UNIQUE, 0, victim, MSG_TYPE_SPELL, MSG_TYPE_SPELL_TARGET,
02705                       "You start hearing voices.", NULL);
02706     }
02707 }
02708 
02726 int cast_transfer(object *op, object *caster, object *spell, int dir) {
02727     object *plyr = NULL;
02728     sint16 x, y;
02729     mapstruct *m;
02730     int mflags;
02731 
02732     m = op->map;
02733     x =  op->x+freearr_x[dir];
02734     y = op->y+freearr_y[dir];
02735 
02736     mflags = get_map_flags(m, &m, x, y, &x, &y);
02737     if (!(mflags&P_OUT_OF_MAP) && mflags&P_IS_ALIVE) {
02738         for (plyr = GET_MAP_OB(m, x, y); plyr != NULL; plyr = plyr->above)
02739             if (plyr != op && QUERY_FLAG(plyr, FLAG_ALIVE))
02740                 break;
02741     }
02742 
02743     /* If we did not find a player in the specified direction, transfer
02744      * to anyone on top of us. This is used for the rune of transference mostly.
02745      */
02746     if (plyr == NULL)
02747         for (plyr = GET_MAP_OB(op->map, op->x, op->y); plyr != NULL; plyr = plyr->above)
02748             if (plyr != op && QUERY_FLAG(plyr, FLAG_ALIVE))
02749                 break;
02750 
02751     if (!plyr) {
02752         draw_ext_info(NDI_BLACK, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
02753                       "There is no one there.", NULL);
02754         return 0;
02755     }
02756 
02757     /* give sp */
02758     if (spell->stats.dam > 0) {
02759         plyr->stats.sp += spell->stats.dam+SP_level_dam_adjust(caster, spell);
02760         charge_mana_effect(plyr, caster_level(caster, spell));
02761         return 1;
02762     /* suck sp away.  Can't suck sp from yourself */
02763     } else if (op != plyr) {
02764         /* old dragin magic used floats.  easier to just use ints and divide by 100 */
02765 
02766         int rate = -spell->stats.dam+SP_level_dam_adjust(caster, spell), sucked;
02767 
02768         if (rate > 95)
02769             rate = 95;
02770 
02771         sucked = (plyr->stats.sp*rate)/100;
02772         plyr->stats.sp -= sucked;
02773         if (QUERY_FLAG(op, FLAG_ALIVE)) {
02774             /* Player doesn't get full credit */
02775             sucked = (sucked*rate)/100;
02776             op->stats.sp += sucked;
02777             if (sucked > 0) {
02778                 charge_mana_effect(op, caster_level(caster, spell));
02779             }
02780         }
02781         return 1;
02782     }
02783     return 0;
02784 }
02785 
02795 void counterspell(object *op, int dir) {
02796     object *tmp, *head, *next;
02797     int mflags;
02798     mapstruct *m;
02799     sint16  sx, sy;
02800 
02801     sx = op->x+freearr_x[dir];
02802     sy = op->y+freearr_y[dir];
02803     m = op->map;
02804     mflags = get_map_flags(m, &m, sx, sy, &sx, &sy);
02805     if (mflags&P_OUT_OF_MAP)
02806         return;
02807 
02808     for (tmp = GET_MAP_OB(m, sx, sy); tmp != NULL; tmp = next) {
02809         next = tmp->above;
02810 
02811         /* Need to look at the head object - otherwise, if tmp
02812          * points to a monster, we don't have all the necessary
02813          * info for it.
02814          */
02815         if (tmp->head)
02816             head = tmp->head;
02817         else
02818             head = tmp;
02819 
02820         /* don't attack our own spells */
02821         if (tmp->owner && tmp->owner == op->owner)
02822             continue;
02823 
02824         /* Basically, if the object is magical and not counterspell,
02825          * we will more or less remove the object.  Don't counterspell
02826          * monsters either.
02827          */
02828 
02829         if (head->attacktype&AT_MAGIC
02830         && !(head->attacktype&AT_COUNTERSPELL)
02831         && !QUERY_FLAG(head, FLAG_MONSTER)
02832         && (op->level > head->level)) {
02833             remove_ob(head);
02834             free_object(head);
02835         } else switch (head->type) {
02836             case SPELL_EFFECT:
02837                 if ((op->level > head->level) && !op->stats.food && !op->speed_left) {
02838                     remove_ob(head);
02839                     free_object(head);
02840                 }
02841                 break;
02842 
02843                 /* I really don't get this rune code that much - that
02844                  * random chance seems really low.
02845                  */
02846             case RUNE:
02847                 if (rndm(0, 149) == 0) {
02848                     head->stats.hp--;  /* weaken the rune */
02849                     if (!head->stats.hp) {
02850                         remove_ob(head);
02851                         free_object(head);
02852                     }
02853                 }
02854                 break;
02855             }
02856     }
02857 }
02858 
02873 int cast_consecrate(object *op, object *caster, object *spell) {
02874     char buf[MAX_BUF];
02875     object *tmp;
02876     const object *god = find_god(determine_god(op));
02877 
02878     if (!god) {
02879         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
02880                       "You can't consecrate anything if you don't worship a god!", NULL);
02881         return 0;
02882     }
02883 
02884     for (tmp = op->below; tmp; tmp = tmp->below) {
02885         if (QUERY_FLAG(tmp, FLAG_IS_FLOOR))
02886             break;
02887         if (tmp->type == HOLY_ALTAR) {
02888             if (tmp->level > caster_level(caster, spell)) {
02889                 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
02890                                      "You are not powerful enough to reconsecrate the %s",
02891                                      "You are not powerful enough to reconsecrate the %s",
02892                                      tmp->name);
02893                 return 0;
02894             } else {
02895                 /* If we got here, we are consecrating an altar */
02896                 object *new_altar;
02897                 int letter;
02898                 archetype *altar_arch;
02899 
02900                 snprintf(buf, MAX_BUF, "altar_");
02901                 letter = strlen(buf);
02902                 strncpy(buf+letter, god->name, MAX_BUF-letter);
02903                 for (; letter < strlen(buf); letter++)
02904                     buf[letter] = tolower(buf[letter]);
02905                 altar_arch = find_archetype(buf);
02906                 if (!altar_arch) {
02907                     draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
02908                                          "You fail to consecrate the altar.", NULL);
02909                     LOG(llevError, "cast_consecrate: can't find altar %s for god %s\n", buf, god->name);
02910                     return 0;
02911                 }
02912                 new_altar = arch_to_object(altar_arch);
02913                 new_altar->x = tmp->x;
02914                 new_altar->y = tmp->y;
02915                 new_altar->level = tmp->level;
02916                 insert_ob_in_map(new_altar, tmp->map, tmp, INS_BELOW_ORIGINATOR);
02917                 remove_ob(tmp);
02918                 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_SUCCESS,
02919                                      "You consecrated the altar to %s!",
02920                                      "You consecrated the altar to %s!",
02921                                      god->name);
02922                 return 1;
02923             }
02924         }
02925     }
02926     draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
02927                   "You are not standing over an altar!", NULL);
02928     return 0;
02929 }
02930 
02954 int animate_weapon(object *op, object *caster, object *spell, int dir) {
02955     object *weapon, *tmp;
02956     char buf[MAX_BUF];
02957     int a, i;
02958     sint16 x, y;
02959     mapstruct *m;
02960     materialtype_t *mt;
02961 
02962     if (!spell->other_arch) {
02963         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
02964                       "Oops, program error!", NULL);
02965         LOG(llevError, "animate_weapon failed: spell %s missing other_arch!\n", spell->name);
02966         return 0;
02967     }
02968 
02969     /* exit if it's not a player using this spell. */
02970     if (op->type != PLAYER)
02971         return 0;
02972 
02973     /* if player already has a golem, abort */
02974     if (op->contr->ranges[range_golem] != NULL && op->contr->golem_count == op->contr->ranges[range_golem]->count) {
02975         control_golem(op->contr->ranges[range_golem], dir);
02976         return 0;
02977     }
02978 
02979     /* if no direction specified, pick one */
02980     if (!dir)
02981         dir = find_free_spot(NULL, op->map, op->x, op->y, 1, 9);
02982 
02983     m = op->map;
02984     x = op->x+freearr_x[dir];
02985     y = op->y+freearr_y[dir];
02986 
02987     /* if there's no place to put the golem, abort */
02988     if ((dir == -1)
02989     || (get_map_flags(m, &m, x, y, &x, &y)&P_OUT_OF_MAP)
02990     || ((spell->other_arch->clone.move_type&GET_MAP_MOVE_BLOCK(m, x, y)) == spell->other_arch->clone.move_type)) {
02991         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
02992                       "There is something in the way.", NULL);
02993         return 0;
02994     }
02995 
02996     /* Use the weapon marked by the player. */
02997     weapon = find_marked_object(op);
02998 
02999     if (!weapon) {
03000         draw_ext_info(NDI_BLACK, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
03001                       "You must mark a weapon to use with this spell!", NULL);
03002         return 0;
03003     }
03004     if (spell->race && strcmp(weapon->arch->name, spell->race)) {
03005         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
03006                       "The spell fails to transform your weapon.", NULL);
03007         return 0;
03008     }
03009     if (weapon->type != WEAPON) {
03010         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
03011                       "You need to mark a weapon to animate it.", NULL);
03012         return 0;
03013     }
03014     if (QUERY_FLAG(weapon, FLAG_UNPAID)) {
03015         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
03016                       "You need to pay for the weapon to animate it.", NULL);
03017         return 0;
03018     }
03019     if (QUERY_FLAG(weapon, FLAG_APPLIED)) {
03020         char wn[MAX_BUF];
03021 
03022         query_name(weapon, wn, MAX_BUF);
03023         draw_ext_info_format(NDI_BLACK, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
03024                              "You need to unequip %s before using it in this spell",
03025                              "You need to unequip %s before using it in this spell",
03026                              wn);
03027         return 0;
03028     }
03029 
03030     if (weapon->nrof > 1) {
03031         tmp = get_split_ob(weapon, 1, NULL, 0);
03032         esrv_update_item(UPD_NROF, op, weapon);
03033         weapon = tmp;
03034     }
03035 
03036     /* create the golem object */
03037     tmp = arch_to_object(spell->other_arch);
03038 
03039     /* if animated by a player, give the player control of the golem */
03040     CLEAR_FLAG(tmp, FLAG_MONSTER);
03041     SET_FLAG(tmp, FLAG_FRIENDLY);
03042     tmp->stats.exp = 0;
03043     add_friendly_object(tmp);
03044     tmp->type = GOLEM;
03045     set_owner(tmp, op);
03046     set_spell_skill(op, caster, spell, tmp);
03047     op->contr->ranges[range_golem] = tmp;
03048     op->contr->shoottype = range_golem;
03049     op->contr->golem_count = tmp->count;
03050 
03051     /* Give the weapon to the golem now.  A bit of a hack to check the
03052      * removed flag - it should only be set if get_split_object was
03053      * used above.
03054      */
03055     if (!QUERY_FLAG(weapon, FLAG_REMOVED))
03056         remove_ob(weapon);
03057     insert_ob_in_ob(weapon, tmp);
03058 
03059     /* To do everything necessary to let a golem use the weapon is a pain,
03060      * so instead, just set it as equipped (otherwise, we need to update
03061      * body_info, skills, etc)
03062      */
03063     SET_FLAG(tmp, FLAG_USE_WEAPON);
03064     SET_FLAG(weapon, FLAG_APPLIED);
03065     fix_object(tmp);
03066 
03067     /* There used to be 'odd' code that basically seemed to take the absolute
03068      * value of the weapon->magic an use that.  IMO, that doesn't make sense -
03069      * if you're using a crappy weapon, it shouldn't be as good.
03070      */
03071 
03072     /* modify weapon's animated wc */
03073     tmp->stats.wc = tmp->stats.wc
03074         -SP_level_range_adjust(caster, spell)
03075         -5*weapon->stats.Dex
03076         -2*weapon->stats.Str
03077         -weapon->magic;
03078     if (tmp->stats.wc < -127)
03079         tmp->stats.wc = -127;
03080 
03081     /* Modify hit points for weapon */
03082     tmp->stats.maxhp = tmp->stats.maxhp
03083         +spell->duration
03084         +SP_level_duration_adjust(caster, spell)
03085         +8*weapon->magic
03086         +12*weapon->stats.Con;
03087     if (tmp->stats.maxhp < 0)
03088         tmp->stats.maxhp = 10;
03089     tmp->stats.hp = tmp->stats.maxhp;
03090 
03091     /* Modify weapon's damage */
03092     tmp->stats.dam = spell->stats.dam
03093         +SP_level_dam_adjust(caster, spell)
03094         +weapon->stats.dam
03095         +weapon->magic
03096         +5*weapon->stats.Str;
03097     if (tmp->stats.dam < 0)
03098         tmp->stats.dam = 127;
03099 
03100     /* attacktype */
03101     if (!tmp->attacktype)
03102         tmp->attacktype = AT_PHYSICAL;
03103 
03104     mt = NULL;
03105     if (op->materialname != NULL)
03106         mt = name_to_material(op->materialname);
03107     if (mt != NULL) {
03108         for (i = 0; i < NROFATTACKS; i++)
03109             tmp->resist[i] = 50-(mt->save[i]*5);
03110         a = mt->save[0];
03111     } else {
03112         for (i = 0; i < NROFATTACKS; i++)
03113             tmp->resist[i] = 5;
03114         a = 10;
03115     }
03116     /* Set weapon's immunity */
03117     tmp->resist[ATNR_CONFUSION] = 100;
03118     tmp->resist[ATNR_POISON] = 100;
03119     tmp->resist[ATNR_SLOW] = 100;
03120     tmp->resist[ATNR_PARALYZE] = 100;
03121     tmp->resist[ATNR_TURN_UNDEAD] = 100;
03122     tmp->resist[ATNR_FEAR] = 100;
03123     tmp->resist[ATNR_DEPLETE] = 100;
03124     tmp->resist[ATNR_DEATH] = 100;
03125     tmp->resist[ATNR_BLIND] = 100;
03126 
03127     /* Improve weapon's armour value according to best save vs. physical of its material */
03128 
03129     if (a > 14)
03130         a = 14;
03131     tmp->resist[ATNR_PHYSICAL] = 100-(int)((100.0-(float)tmp->resist[ATNR_PHYSICAL])/(30.0-2.0*a));
03132 
03133     /* Determine golem's speed */
03134     tmp->speed = 0.4+0.1*SP_level_range_adjust(caster, spell);
03135 
03136     if (tmp->speed > 3.33)
03137         tmp->speed = 3.33;
03138 
03139     if (!spell->race) {
03140         snprintf(buf, sizeof(buf), "animated %s", weapon->name);
03141         if (tmp->name)
03142             free_string(tmp->name);
03143         tmp->name = add_string(buf);
03144 
03145         tmp->face = weapon->face;
03146         tmp->animation_id = weapon->animation_id;
03147         tmp->anim_speed = weapon->anim_speed;
03148         tmp->last_anim = weapon->last_anim;
03149         tmp->state = weapon->state;
03150         if (QUERY_FLAG(weapon, FLAG_ANIMATE)) {
03151             SET_FLAG(tmp, FLAG_ANIMATE);
03152         } else {
03153             CLEAR_FLAG(tmp, FLAG_ANIMATE);
03154         }
03155         update_ob_speed(tmp);
03156     }
03157 
03158     /*  make experience increase in proportion to the strength of the summoned creature. */
03159     tmp->stats.exp *= 1+(MAX(spell->stats.maxgrace, spell->stats.sp)/caster_level(caster, spell));
03160 
03161     tmp->speed_left = -1;
03162     tmp->x = x;
03163     tmp->y = y;
03164     tmp->direction = dir;
03165     insert_ob_in_map(tmp, m, op, 0);
03166     return 1;
03167 }
03168 
03183 int cast_change_map_lightlevel(object *op, object *caster, object *spell) {
03184     int success;
03185 
03186     if (!op->map)
03187         return 0;  /* shouldnt happen */
03188 
03189     success = change_map_light(op->map, spell->stats.dam);
03190     if (!success) {
03191         if (spell->stats.dam < 0)
03192             draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
03193                           "It can be no brighter here.", NULL);
03194         else
03195             draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
03196                           "It can be no darker here.", NULL);
03197     }
03198     return success;
03199 }
03200 
03213 int create_aura(object *op, object *caster, object *spell) {
03214     int refresh = 0;
03215     object *new_aura;
03216 
03217     new_aura = present_arch_in_ob(spell->other_arch, op);
03218     if (new_aura)
03219         refresh = 1;
03220     else
03221         new_aura = arch_to_object(spell->other_arch);
03222 
03223     new_aura->duration = spell->duration+10*SP_level_duration_adjust(caster, spell);
03224     if (op->type == PLAYER)
03225         store_spell_expiry(new_aura);
03226 
03227     new_aura->stats.dam = spell->stats.dam+SP_level_dam_adjust(caster, spell);
03228 
03229     set_owner(new_aura, op);
03230     set_spell_skill(op, caster, spell, new_aura);
03231     new_aura->attacktype = spell->attacktype;
03232 
03233     new_aura->level = caster_level(caster, spell);
03234     if (refresh)
03235         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_SUCCESS,
03236                       "You recast the spell while in effect.", NULL);
03237     else
03238         insert_ob_in_ob(new_aura, op);
03239     return 1;
03240 }
03241 
03257 int write_mark(object *op, object *spell, const char *msg) {
03258     char rune[HUGE_BUF];
03259     object *tmp;
03260 
03261     if (!msg || msg[0] == 0) {
03262         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
03263                       "Write what?", NULL);
03264         return 0;
03265     }
03266 
03267     if (strcasestr_local(msg, "endmsg")) {
03268         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
03269                       "Trying to cheat are we?", NULL);
03270         LOG(llevInfo, "write_rune: player %s tried to write bogus rune %s\n", op->name, msg);
03271         return 0;
03272     }
03273 
03274     if (!spell->other_arch)
03275         return 0;
03276     tmp = arch_to_object(spell->other_arch);
03277     strncpy(rune, msg, HUGE_BUF-2);
03278     rune[HUGE_BUF-2] = 0;
03279     strcat(rune, "\n");
03280     tmp->race = add_string(op->name);   /*Save the owner of the rune*/
03281     tmp->msg = add_string(rune);
03282     tmp->x = op->x;
03283     tmp->y = op->y;
03284     insert_ob_in_map(tmp, op->map, op, INS_BELOW_ORIGINATOR);
03285     return 1;
03286 }