Crossfire Server, Branch 1.12  R12190
spell_util.c
Go to the documentation of this file.
00001 /*
00002  * static char *rcsid_spell_util_c =
00003  *   "$Id: spell_util.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) 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 
00035 #include <global.h>
00036 #include <spells.h>
00037 #include <object.h>
00038 #include <errno.h>
00039 #ifndef __CEXTRACT__
00040 #include <sproto.h>
00041 #endif
00042 #include <sounds.h>
00043 #include <assert.h>
00044 
00045 extern const char *const spell_mapping[];
00046 
00060 object *find_random_spell_in_ob(object *ob, const char *skill) {
00061     int k = 0, s;
00062     object *tmp;
00063 
00064     for (tmp = ob->inv; tmp; tmp = tmp->below)
00065         if (tmp->type == SPELL && (!skill || tmp->skill == skill))
00066             k++;
00067 
00068     /* No spells, no need to progess further */
00069     if (!k)
00070         return NULL;
00071 
00072     s = RANDOM()%k;
00073 
00074     for (tmp = ob->inv; tmp; tmp = tmp->below)
00075         if (tmp->type == SPELL && (!skill || tmp->skill == skill)) {
00076             if (!s)
00077                 return tmp;
00078             else
00079                 s--;
00080         }
00081     /* Should never get here, but just in case */
00082     return NULL;
00083 }
00084 
00105 void set_spell_skill(object *op, object *caster, object *spob, object *dest) {
00106     if (dest->skill)
00107         FREE_AND_CLEAR_STR(dest->skill);
00108     if (caster == op && spob->skill)
00109         dest->skill = add_refcount(spob->skill);
00110     else if (caster->skill)
00111         dest->skill = add_refcount(caster->skill);
00112 }
00113 
00120 void check_spells(void) {
00121 #ifdef SPELL_DEBUG
00122     int i;
00123     archetype *at;
00124 
00125     LOG(llevDebug, "Checking spells...\n");
00126 
00127     for (at = first_archetype; at; at = at->next) {
00128         if (at->clone.type == SPELL) {
00129             if (at->clone.skill) {
00130                 for (i = 1; i < NUM_SKILLS; i++)
00131                     if (!strcmp(skill_names[i], at->clone.skill))
00132                         break;
00133                 if (i == NUM_SKILLS) {
00134                     LOG(llevError, "Spell %s has improper associated skill %s\n", at->name, at->clone.skill);
00135                 }
00136             }
00137             /* other_arch is already checked for in the loader */
00138         }
00139     }
00140 
00141     i = 0;
00142     while (spell_mapping[i]) {
00143         if (!find_archetype(spell_mapping[i])) {
00144             LOG(llevError, "Unable to find spell mapping %s (%i)\n", spell_mapping[i], i);
00145         }
00146         i++;
00147     }
00148     LOG(llevDebug, "Checking spells completed.\n");
00149 #endif
00150 }
00151 
00157 void dump_spells(void) {
00158     archetype *at;
00159 
00160     for (at = first_archetype; at; at = at->next) {
00161         if (at->clone.type == SPELL) {
00162             fprintf(stderr, "%s:%s:%s:%s:%d\n", at->clone.name ? at->clone.name : "null",
00163                     at->name, at->clone.other_arch ? at->clone.other_arch->name : "null",
00164                     at->clone.skill ? at->clone.skill : "null", at->clone.level);
00165         }
00166     }
00167 }
00168 
00182 void spell_effect(object *spob, int x, int y, mapstruct *map, object *originator) {
00183 
00184     if (spob->other_arch !=  NULL) {
00185         object *effect = arch_to_object(spob->other_arch);
00186 
00187         effect->x = x;
00188         effect->y = y;
00189 
00190         insert_ob_in_map(effect, map, originator, 0);
00191     }
00192 }
00193 
00207 int min_casting_level(const object *caster, const object *spell) {
00208     int new_level;
00209 
00210     if (caster->path_denied&spell->path_attuned) {
00211         /* This case is not a bug, just the fact that this function is
00212          * usually called BEFORE checking for path_deny. -AV
00213          */
00214         return 1;
00215     }
00216     new_level = spell->level
00217                 +((caster->path_repelled&spell->path_attuned) ? +2 : 0)
00218                 +((caster->path_attuned&spell->path_attuned) ? -2 : 0);
00219     return MAX(new_level, 1);
00220 }
00221 
00222 
00237 int caster_level(const object *caster, const object *spell) {
00238     int level = caster->level;
00239 
00240     /* If this is a player, try to find the matching skill */
00241     if (caster->type == PLAYER && spell->skill) {
00242         int i;
00243 
00244         for (i = 0; i < NUM_SKILLS; i++)
00245             if (caster->contr->last_skill_ob[i]
00246             && caster->contr->last_skill_ob[i]->skill == spell->skill) {
00247                 level = caster->contr->last_skill_ob[i]->level;
00248                 break;
00249             }
00250     }
00251     /* Got valid caster level.  Now adjust for attunement */
00252     level += ((caster->path_repelled&spell->path_attuned) ? -2 : 0)
00253             +((caster->path_attuned&spell->path_attuned) ? 2 : 0);
00254 
00255     /* Always make this at least 1.  If this is zero, we get divide by zero
00256      * errors in various places.
00257      */
00258     if (level < 1)
00259         level = 1;
00260     return level;
00261 }
00262 
00281 sint16 SP_level_spellpoint_cost(object *caster, object *spell, int flags) {
00282     int sp, grace, level = caster_level(caster, spell);
00283 
00284     if (settings.spellpoint_level_depend == TRUE) {
00285         if (spell->stats.sp && spell->stats.maxsp) {
00286             sp = (int)(spell->stats.sp*(1.0+MAX(0, (float)(level-spell->level)/(float)spell->stats.maxsp)));
00287         } else
00288             sp = spell->stats.sp;
00289 
00290         sp *= PATH_SP_MULT(caster, spell);
00291         if (!sp && spell->stats.sp)
00292             sp = 1;
00293 
00294         if (spell->stats.grace && spell->stats.maxgrace) {
00295             grace = (int)(spell->stats.grace*(1.0+MAX(0, (float)(level-spell->level)/(float)spell->stats.maxgrace)));
00296         } else
00297             grace = spell->stats.grace;
00298 
00299         grace *= PATH_SP_MULT(caster, spell);
00300         if (spell->stats.grace && !grace)
00301             grace = 1;
00302     } else {
00303         sp = spell->stats.sp*PATH_SP_MULT(caster, spell);
00304         if (spell->stats.sp && !sp)
00305             sp = 1;
00306         grace = spell->stats.grace*PATH_SP_MULT(caster, spell);
00307         if (spell->stats.grace && !grace)
00308             grace = 1;
00309     }
00310     if (flags == SPELL_HIGHEST)
00311         return MAX(sp, grace);
00312     else if (flags == SPELL_GRACE)
00313         return grace;
00314     else if (flags == SPELL_MANA)
00315         return sp;
00316     else {
00317         LOG(llevError, "SP_level_spellpoint_cost: Unknown flags passed: %d\n", flags);
00318         return 0;
00319     }
00320 }
00321 
00332 int SP_level_dam_adjust(const object *caster, const object *spob) {
00333     int level = caster_level(caster, spob);
00334     int adj = level-min_casting_level(caster, spob);
00335 
00336     if (adj < 0)
00337         adj = 0;
00338     if (spob->dam_modifier)
00339         adj /= spob->dam_modifier;
00340     else
00341         adj = 0;
00342     return adj;
00343 }
00344 
00357 int SP_level_duration_adjust(const object *caster, const object *spob) {
00358     int level = caster_level(caster, spob);
00359     int adj = level-min_casting_level(caster, spob);
00360 
00361     if (adj < 0)
00362         adj = 0;
00363     if (spob->duration_modifier)
00364         adj /= spob->duration_modifier;
00365     else
00366         adj = 0;
00367 
00368     return adj;
00369 }
00370 
00383 int SP_level_range_adjust(const object *caster, const object *spob) {
00384     int level = caster_level(caster, spob);
00385     int adj = level-min_casting_level(caster, spob);
00386 
00387     if (adj < 0)
00388         adj = 0;
00389     if (spob->range_modifier)
00390         adj /= spob->range_modifier;
00391     else
00392         adj = 0;
00393 
00394     return adj;
00395 }
00396 
00408 object *check_spell_known(object *op, const char *name) {
00409     object *spop;
00410 
00411     for (spop = op->inv; spop; spop = spop->below)
00412         if (spop->type == SPELL && !strcmp(spop->name, name))
00413             return spop;
00414 
00415     return NULL;
00416 }
00417 
00430 object *lookup_spell_by_name(object *op, const char *spname) {
00431     object *spob1 = NULL, *spob2 = NULL, *spob;
00432     int nummatch = 0;
00433 
00434     if (spname == NULL)
00435         return NULL;
00436 
00437     /* Try to find the spell.  We store the results in spob1
00438      * and spob2 - spob1 is only taking the length of
00439      * the past spname, spob2 uses the length of the spell name.
00440      */
00441     for (spob = op->inv; spob; spob = spob->below) {
00442         if (spob->type == SPELL) {
00443             if (!strncmp(spob->name, spname, strlen(spname))) {
00444                 if (strlen(spname) == strlen(spob->name))
00445                     /* Perfect match, return it. */
00446                     return spob;
00447                 nummatch++;
00448                 spob1 = spob;
00449             } else if (!strncmp(spob->name, spname, strlen(spob->name))) {
00450                 /* if spells have ambiguous names, it makes matching
00451                  * really difficult.  (eg, fire and fireball would
00452                  * fall into this category).  It shouldn't be hard to
00453                  * make sure spell names don't overlap in that fashion.
00454                  */
00455                 if (spob2)
00456                     LOG(llevError, "Found multiple spells with overlapping base names: %s, %s\n", spob2->name, spob->name);
00457                 spob2 = spob;
00458             }
00459         }
00460     }
00461     /* if we have best match, return it.  Otherwise, if we have one match
00462      * on the loser match, return that, otehrwise null
00463      */
00464     if (spob2)
00465         return spob2;
00466     if (spob1 && nummatch == 1)
00467         return spob1;
00468     return NULL;
00469 }
00470 
00490 int reflwall(mapstruct *m, int x, int y, object *sp_op) {
00491     object *op;
00492 
00493     if (OUT_OF_REAL_MAP(m, x, y))
00494         return 0;
00495     for (op = GET_MAP_OB(m, x, y); op != NULL; op = op->above)
00496         if (QUERY_FLAG(op, FLAG_REFL_SPELL)
00497         && (!QUERY_FLAG(op, FLAG_ALIVE) || (rndm(0, 99)) < 90-(sp_op->level/10)))
00498             return 1;
00499 
00500     return 0;
00501 }
00502 
00517 int cast_create_obj(object *op, object *new_op, int dir) {
00518     mapstruct *m;
00519     sint16  sx, sy;
00520 
00521     if (dir
00522     && ((get_map_flags(op->map, &m, op->x+freearr_x[dir], op->y+freearr_y[dir], &sx, &sy)&P_OUT_OF_MAP)
00523         || OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, sx, sy)))) {
00524         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_INFO,
00525                       "Something is in the way. You cast it at your feet.", NULL);
00526         dir = 0;
00527     }
00528     new_op->x = op->x+freearr_x[dir];
00529     new_op->y = op->y+freearr_y[dir];
00530     if (dir == 0)
00531         insert_ob_in_map(new_op, op->map, op, INS_BELOW_ORIGINATOR);
00532     else
00533         insert_ob_in_map(new_op, op->map, op, 0);
00534     return dir;
00535 }
00536 
00555 int ok_to_put_more(mapstruct *m, sint16 x, sint16 y, object *op, uint32 immune_stop) {
00556     object *tmp;
00557     int mflags;
00558     mapstruct *mp;
00559 
00560     mp = m;
00561     mflags = get_map_flags(m, &mp, x, y, &x, &y);
00562 
00563     if (mflags&P_OUT_OF_MAP)
00564         return 0;
00565 
00566     if (OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(mp, x, y)))
00567         return 0;
00568 
00569     for (tmp = GET_MAP_OB(mp, x, y); tmp != NULL; tmp = tmp->above) {
00570         /* If there is a counterspell on the space, and this
00571          * object is using magic, don't progess.  I believe we could
00572          * leave this out and let in progress, and other areas of the code
00573          * will then remove it, but that would seem to to use more
00574          * resources, and may not work as well if a player is standing
00575          * on top of a counterwall spell (may hit the player before being
00576          * removed.)  On the other hand, it may be more dramatic for the
00577          * spell to actually hit the counterwall and be sucked up.
00578          */
00579         if ((tmp->attacktype&AT_COUNTERSPELL)
00580         && (tmp->type != PLAYER)
00581         && !QUERY_FLAG(tmp, FLAG_MONSTER)
00582         && (tmp->type != WEAPON)
00583         && (tmp->type != BOW)
00584         && (tmp->type != ARROW)
00585         && (tmp->type != GOLEM)
00586         && (immune_stop&AT_MAGIC))
00587             return 0;
00588 
00589         /* This is to prevent 'out of control' spells.  Basically, this
00590          * limits one spell effect per space per spell.  This is definitely
00591          * needed for performance reasons, and just for playability I believe.
00592          * there are no such things as multispaced spells right now, so
00593          * we don't need to worry about the head.
00594          * We only need to go down this path is maxhp is set on both objects -
00595          * otherwise, no reason to check.  But if we do check, we need to
00596          * do some extra work, looking in the spell_tags[] of each object,
00597          * if they have it set.
00598          */
00599         if (tmp->type == op->type
00600         && tmp->subtype == op->subtype
00601         && tmp->stats.maxhp
00602         && op->stats.maxhp) {
00603             if ((tmp->stats.maxhp == op->stats.maxhp)
00604             || (tmp->spell_tags && OB_SPELL_TAG_MATCH(tmp, op->stats.maxhp))
00605             || (op->spell_tags && OB_SPELL_TAG_MATCH(op, tmp->stats.maxhp))) {
00606                 statistics.spell_suppressions++;
00607                 return 0;
00608             }
00609 
00610             /* if both objects have spell tags, then if the two tags entries
00611              * from either match, that also counts.  Need to check
00612              * the spell_tags, because 0 values are allowed to match
00613              */
00614             if (op->spell_tags && tmp->spell_tags) {
00615                 int i;
00616 
00617                 for (i = 0; i < SPELL_TAG_SIZE; i++) {
00618                     if (op->spell_tags[i] && op->spell_tags[i] == tmp->spell_tags[i])
00619                         statistics.spell_suppressions++;
00620                     return 0;
00621                 }
00622             }
00623         }
00624         /* Perhaps we should also put checks in for no magic and unholy
00625          * ground to prevent it from moving along?
00626          */
00627     }
00628     /* If it passes the above tests, it must be OK */
00629     return 1;
00630 }
00631 
00653 int fire_arch_from_position(object *op, object *caster, sint16 x, sint16 y, int dir, object *spell) {
00654     object *tmp;
00655     int mflags;
00656     mapstruct *m;
00657 
00658     if (spell->other_arch == NULL)
00659         return 0;
00660 
00661     m = op->map;
00662     mflags = get_map_flags(m, &m, x, y, &x, &y);
00663     if (mflags&P_OUT_OF_MAP) {
00664         return 0;
00665     }
00666 
00667     tmp = arch_to_object(spell->other_arch);
00668     if (tmp == NULL)
00669         return 0;
00670 
00671     if (OB_TYPE_MOVE_BLOCK(tmp, GET_MAP_MOVE_BLOCK(m, x, y))) {
00672         if (caster->type == PLAYER)
00673             /* If caster is not player, it's for instance a swarm, so don't say there's an issue. */
00674             draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
00675                           "You can't cast the spell on top of a wall!", NULL);
00676         free_object(tmp);
00677         return 0;
00678     }
00679 
00680 
00681 
00682     tmp->stats.dam = spell->stats.dam+SP_level_dam_adjust(caster, spell);
00683     tmp->duration = spell->duration+SP_level_duration_adjust(caster, spell);
00684     /* code in time.c uses food for some things, duration for others */
00685     tmp->stats.food = tmp->duration;
00686     tmp->range = spell->range+SP_level_range_adjust(caster, spell);
00687     tmp->attacktype = spell->attacktype;
00688     tmp->x = x;
00689     tmp->y = y;
00690     tmp->direction = dir;
00691     if (get_owner(op) != NULL)
00692         copy_owner(tmp, op);
00693     else
00694         set_owner(tmp, op);
00695     tmp->level = caster_level(caster, spell);
00696     set_spell_skill(op, caster, spell, tmp);
00697 
00698     /* needed for AT_HOLYWORD, AT_GODPOWER stuff */
00699     if (tmp->attacktype&AT_HOLYWORD || tmp->attacktype&AT_GODPOWER) {
00700         if (!tailor_god_spell(tmp, op))
00701             return 0;
00702     }
00703     if (QUERY_FLAG(tmp, FLAG_IS_TURNABLE))
00704         SET_ANIMATION(tmp, dir);
00705 
00706     if ((tmp = insert_ob_in_map(tmp, m, op, 0)) == NULL)
00707         return 1;
00708 
00709     ob_process(tmp);
00710 
00711     return 1;
00712 }
00713 
00714 
00715 
00716 /*****************************************************************************
00717  *
00718  * Code related to rods - perhaps better located in another file?
00719  *
00720  ****************************************************************************/
00721 
00728 void regenerate_rod(object *rod) {
00729     if (rod->stats.hp < rod->stats.maxhp) {
00730         rod->stats.hp += 1+rod->stats.maxhp/10;
00731 
00732         if (rod->stats.hp > rod->stats.maxhp)
00733             rod->stats.hp = rod->stats.maxhp;
00734     }
00735 }
00736 
00743 void drain_rod_charge(object *rod) {
00744     rod->stats.hp -= SP_level_spellpoint_cost(rod, rod->inv, SPELL_HIGHEST);
00745 }
00746 
00753 void drain_wand_charge(object *wand) {
00754     assert(wand->type == WAND);
00755 
00756     if (!(--wand->stats.food)) {
00757         object *tmp;
00758         if (wand->arch) {
00759             CLEAR_FLAG(wand, FLAG_ANIMATE);
00760             wand->face = wand->arch->clone.face;
00761             wand->speed = 0;
00762             update_ob_speed(wand);
00763         }
00764         if ((tmp = get_player_container(wand)))
00765             esrv_update_item(UPD_ANIM, tmp, wand);
00766     }
00767 }
00768 
00779 object *find_target_for_friendly_spell(object *op, int dir) {
00780     object *tmp;
00781     mapstruct *m;
00782     sint16 x, y;
00783     int mflags;
00784 
00785     /* I don't really get this block - if op isn't a player or rune,
00786      * we then make the owner of this object the target.
00787      * The owner could very well be no where near op.
00788      */
00789     if (op->type != PLAYER && op->type != RUNE) {
00790         tmp = get_owner(op);
00791         /* If the owner does not exist, or is not a monster, than apply the spell
00792          * to the caster.
00793          */
00794         if (!tmp || !QUERY_FLAG(tmp, FLAG_MONSTER))
00795             tmp = op;
00796     } else {
00797         m = op->map;
00798         x =  op->x+freearr_x[dir];
00799         y =  op->y+freearr_y[dir];
00800 
00801         mflags = get_map_flags(m, &m, x, y, &x, &y);
00802 
00803         if (mflags&P_OUT_OF_MAP)
00804             tmp = NULL;
00805         else {
00806             for (tmp = GET_MAP_OB(m, x, y); tmp != NULL; tmp = tmp->above) {
00807                 if (tmp->type == PLAYER)
00808                     break;
00809             }
00810         }
00811     }
00812     /* didn't find a player there, look in current square for a player */
00813     if (tmp == NULL)
00814         for (tmp = GET_MAP_OB(op->map, op->x, op->y); tmp != NULL; tmp = tmp->above) {
00815             if (tmp->type == PLAYER)
00816                 break;
00817             /* Don't forget to browse inside transports ! - gros 2006/07/25 */
00818             if (tmp->type == TRANSPORT) {
00819                 object *inv;
00820 
00821                 for (inv = tmp->inv; inv; inv = inv->below) {
00822                     if ((inv->type == PLAYER) && (op == inv))
00823                         return inv;
00824                 }
00825             }
00826         }
00827     return tmp;
00828 }
00829 
00830 
00831 
00852 int spell_find_dir(mapstruct *m, int x, int y, object *exclude) {
00853     int i, max = SIZEOFFREE;
00854     sint16 nx, ny;
00855     int owner_type = 0, mflags;
00856     object *tmp;
00857     mapstruct *mp;
00858 
00859     if (exclude && exclude->head)
00860         exclude = exclude->head;
00861     if (exclude && exclude->type)
00862         owner_type = exclude->type;
00863 
00864     for (i = rndm(1, 8); i < max; i++) {
00865         nx = x+freearr_x[i];
00866         ny = y+freearr_y[i];
00867         mp = m;
00868         mflags = get_map_flags(m, &mp, nx, ny, &nx, &ny);
00869         if (mflags&(P_OUT_OF_MAP|P_BLOCKSVIEW))
00870             continue;
00871 
00872         tmp = GET_MAP_OB(mp, nx, ny);
00873 
00874         while (tmp != NULL
00875             && (((owner_type == PLAYER && !QUERY_FLAG(tmp, FLAG_MONSTER) && !QUERY_FLAG(tmp, FLAG_GENERATOR) && !(tmp->type == PLAYER && op_on_battleground(tmp, NULL, NULL, NULL)))
00876                     || (owner_type != PLAYER && tmp->type != PLAYER))
00877                 || (tmp == exclude || (tmp->head && tmp->head == exclude))))
00878             tmp = tmp->above;
00879 
00880         if (tmp != NULL && can_see_monsterP(m, x, y, i))
00881             return freedir[i];
00882     }
00883     return -1;  /* flag for "keep going the way you were" */
00884 }
00885 
00886 
00887 
00901 static int put_a_monster(object *op, const char *monstername) {
00902     object *tmp, *head = NULL, *prev = NULL;
00903     archetype *at;
00904     int dir;
00905 
00906     /* Handle cases where we are passed a bogus mosntername */
00907 
00908     if ((at = find_archetype(monstername)) == NULL)
00909         return 0;
00910 
00911     /* find a free square nearby
00912      * first we check the closest square for free squares
00913      */
00914 
00915     dir = find_first_free_spot(&at->clone, op->map, op->x, op->y);
00916     if (dir != -1) {
00917         /* This is basically grabbed for generate monster.  Fixed 971225 to
00918          * insert multipart monsters properly
00919          */
00920         while (at != NULL) {
00921             tmp = arch_to_object(at);
00922             tmp->x = op->x+freearr_x[dir]+at->clone.x;
00923             tmp->y = op->y+freearr_y[dir]+at->clone.y;
00924             tmp->map = op->map;
00925             if (head) {
00926                 tmp->head = head;
00927                 prev->more = tmp;
00928             }
00929             if (!head)
00930                 head = tmp;
00931             prev = tmp;
00932             at = at->more;
00933         }
00934 
00935         if (head->randomitems)
00936             create_treasure(head->randomitems, head, GT_INVISIBLE, op->map->difficulty, 0);
00937 
00938         insert_ob_in_map(head, op->map, op, 0);
00939 
00940         /* thought it'd be cool to insert a burnout, too.*/
00941         tmp = create_archetype("burnout");
00942         tmp->map = op->map;
00943         tmp->x = op->x+freearr_x[dir];
00944         tmp->y = op->y+freearr_y[dir];
00945         insert_ob_in_map(tmp, op->map, op, 0);
00946         return 1;
00947     } else {
00948         return 0;
00949     }
00950 }
00951 
00970 int summon_hostile_monsters(object *op, int n, const char *monstername) {
00971     int i, put = 0;
00972 
00973     for (i = 0; i < n; i++)
00974         put += put_a_monster(op, monstername);
00975 
00976     return put;
00977 }
00978 
00979 
01004 void shuffle_attack(object *op, int change_face) {
01005     int i;
01006 
01007     i = rndm(0, 21);
01008     op->attacktype = ATTACKS[i].attacktype|AT_MAGIC;
01009     if (change_face) {
01010         SET_ANIMATION(op, ATTACKS[i].face);
01011     }
01012 }
01013 
01014 
01025 static void prayer_failure(object *op, int failure, int power) {
01026     const char *godname;
01027     object *tmp;
01028 
01029     if (!strcmp((godname = determine_god(op)), "none"))
01030         godname = "Your spirit";
01031 
01032     if (failure <= -20 && failure > -40) { /* wonder */
01033         draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01034                              "%s gives a sign to renew your faith.",
01035                              "%s gives a sign to renew your faith.",
01036                              godname);
01037         tmp = create_archetype(SPELL_WONDER);
01038         cast_cone(op, op, 0, tmp);
01039         free_object(tmp);
01040     } else if (failure <= -40 && failure > -60) { /* confusion */
01041         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01042                       "Your diety touches your mind!", NULL);
01043         confuse_living(op, op, 99);
01044     } else if (failure <= -60 && failure > -150) { /* paralysis */
01045         draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01046                              "%s requires you to pray NOW. You comply, ignoring all else.",
01047                              "%s requires you to pray NOW. You comply, ignoring all else.",
01048                              godname);
01049 
01050         paralyze_living(op, op, 99);
01051     } else if (failure <= -150) { /* blast the immediate area */
01052         tmp = create_archetype(GOD_POWER);
01053         draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01054                              "%s smites you!",
01055                              "%s smites you!",
01056                              godname);
01057         /* Put a cap on power - this is effectively cost of the spell minus
01058          * characters current grace.  Thus, if spell costs 30 grace and
01059          * character has -100 grace, this is cast as a level 130 spell.
01060          * Things start to break in those cases.
01061          */
01062         cast_magic_storm(op, tmp, power>50?50:power);
01063     }
01064 }
01065 
01078 void spell_failure(object *op, int failure, int power, object *skill) {
01079     object *tmp;
01080 
01081     if (settings.spell_failure_effects == FALSE)
01082         return;
01083 
01084     if (failure <= -20 && failure > -40) { /* wonder */
01085         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01086                       "Your spell causes an unexpected effect.", NULL);
01087         tmp = create_archetype(SPELL_WONDER);
01088         cast_cone(op, op, 0, tmp);
01089         free_object(tmp);
01090     } else if (failure <= -40 && failure > -60) { /* confusion */
01091         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01092                       "Your magic recoils on you, making you confused!", NULL);
01093         confuse_living(op, op, 99);
01094     } else if (failure <= -60 && failure > -80) { /* paralysis */
01095         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01096                       "Your magic stuns you!", NULL);
01097         paralyze_living(op, op, 99);
01098     } else if (failure <= -80) { /* blast the immediate area */
01099         object *tmp;
01100 
01101         /* Safety check to make sure we don't get any mana storms in scorn */
01102         if (get_map_flags(op->map, NULL, op->x, op->y, NULL, NULL)&P_NO_MAGIC) {
01103             draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01104                           "The magic warps and you are turned inside out!", NULL);
01105             hit_player(op, 9998, op, AT_INTERNAL, 1);
01106         } else {
01107             draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01108                           "You lose control of the mana! The uncontrolled magic blasts you!",
01109                           NULL);
01110             tmp = create_archetype(LOOSE_MANA);
01111             tmp->level = skill->level;
01112             tmp->x = op->x;
01113             tmp->y = op->y;
01114 
01115             /* increase the area of destruction a little for more powerful spells */
01116             tmp->range += isqrt(power);
01117 
01118             if (power > 25)
01119                 tmp->stats.dam = 25+isqrt(power);
01120             else
01121                 tmp->stats.dam = power; /* nasty recoils! */
01122 
01123             tmp->stats.maxhp = tmp->count;
01124             insert_ob_in_map(tmp, op->map, NULL, 0);
01125         }
01126     }
01127 }
01128 
01134 static int can_be_transmuted(object *op) {
01135     if (op->invisible)
01136         return 0;
01137 
01138     if (op->type == POTION || op->type == SCROLL || op->type == WAND || op->type == ROD || op->type == WEAPON)
01139         return 1;
01140 
01141     return 0;
01142 }
01143 
01156 static void transmute_item_to_flower(object *op) {
01157     object *force;
01158     object *item;
01159     object *flower;
01160     object *first = NULL;
01161     int count = 0;
01162     char name[HUGE_BUF];
01163 
01164     for (item = op->inv; item; item = item->below) {
01165         if (can_be_transmuted(item)) {
01166             if (!first)
01167                 first = item;
01168             count++;
01169         }
01170     }
01171 
01172     if (count == 0)
01173         return;
01174 
01175     count = rndm(0, count-1);
01176     for (item = first; item; item = item->below) {
01177         if (can_be_transmuted(item)) {
01178             count--;
01179             if (count < 0)
01180                 break;
01181         }
01182     }
01183 
01184     if (!item)
01185         return;
01186 
01187     force = create_archetype(FORCE_NAME);
01188     force->duration = 100+rndm(0, 10)*100;
01189     force->subtype = FORCE_TRANSFORMED_ITEM;
01190     force->speed = 1;
01191     update_ob_speed(force);
01192 
01193     flower = create_archetype("flowers_permanent");
01194 
01195     if (QUERY_FLAG(item, FLAG_APPLIED))
01196         manual_apply(op, item, AP_NOPRINT|AP_IGNORE_CURSE|AP_UNAPPLY);
01197     remove_ob(item);
01198     flower->weight = item->nrof ? item->nrof*item->weight : item->weight;
01199     item->weight = 0;
01200     esrv_del_item(op->contr, item->count);
01201     insert_ob_in_ob(item, force);
01202 
01203     query_short_name(item, name, HUGE_BUF);
01204     draw_ext_info_format(NDI_UNIQUE, 0, op,
01205                          MSG_TYPE_ITEM, MSG_TYPE_ITEM_CHANGE,
01206                          "Your %s turns to a flower!",
01207                          "Your %s turns to a flower!",
01208                          name);
01209 
01210     insert_ob_in_ob(force, flower);
01211     flower = insert_ob_in_ob(flower, op);
01212     esrv_send_item(op, flower);
01213 }
01214 
01225 static void swap_random_stats(object *op) {
01226     object *force;
01227     int first, second;
01228 
01229     first = RANDOM()%NUM_STATS;
01230     second = RANDOM()%(NUM_STATS-1);
01231     if (second >= first)
01232         second++;
01233 
01234     draw_ext_info_format(NDI_UNIQUE, 0, op,
01235                          MSG_TYPE_VICTIM, MSG_TYPE_VICTIM_SPELL,
01236                          "You suddenly feel really weird!",
01237                          "You suddenly feel really weird!");
01238 
01239     force = create_archetype(FORCE_NAME);
01240     force->duration = 100+rndm(0, 10)*100;
01241     force->speed = 1;
01242     SET_FLAG(force, FLAG_APPLIED);
01243     set_attr_value(&force->stats, second, get_attr_value(&op->stats, first)-get_attr_value(&op->stats, second));
01244     set_attr_value(&force->stats, first, get_attr_value(&op->stats, second)-get_attr_value(&op->stats, first));
01245     update_ob_speed(force);
01246     insert_ob_in_ob(force, op);
01247     change_abil(op, force);
01248     fix_object(op);
01249 }
01250 
01261 static void handle_spell_confusion(object *op) {
01262     switch (RANDOM()%2) {
01263     case 0:
01264         transmute_item_to_flower(op);
01265         break;
01266 
01267     case 1:
01268         swap_random_stats(op);
01269         break;
01270     }
01271 }
01272 
01308 int cast_spell(object *op, object *caster, int dir, object *spell_ob, char *stringarg) {
01309 
01310     const char *godname;
01311     int success = 0, mflags, cast_level = 0, old_shoottype;
01312     object *skill = NULL;
01313     int confusion_effect = 0;
01314 
01315     old_shoottype = op->contr ? op->contr->shoottype : 0;
01316 
01317     if (!spell_ob) {
01318         LOG(llevError, "cast_spell: null spell object passed\n");
01319         return 0;
01320     }
01321     if (!strcmp((godname = determine_god(op)), "none"))
01322         godname = "A random spirit";
01323 
01324     /* the caller should set caster to op if appropriate */
01325     if (!caster) {
01326         LOG(llevError, "cast_spell: null caster object passed\n");
01327         return 0;
01328     }
01329     if (spell_ob->anim_suffix)
01330         apply_anim_suffix(caster, spell_ob->anim_suffix);
01331 
01332     /* Handle some random effect if confused. */
01333     if (QUERY_FLAG(op, FLAG_CONFUSED) && caster == op && op->type == PLAYER) {
01334         if (rndm(0, 5) < 4) {
01335             spell_ob = find_random_spell_in_ob(op, NULL);
01336             draw_ext_info_format(NDI_UNIQUE, 0, op,
01337                                  MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01338                                  "In your confused state, you're not sure of what you cast!",
01339                                  "In your confused state, you're not sure of what you cast!");
01340         } else
01341             /* We fall through to deplate sp/gr, and do some checks. */
01342             confusion_effect = 1;
01343     }
01344 
01345     /* if caster is a spell casting object, this normally shouldn't be
01346      * an issue, because they don't have any spellpaths set up.
01347      */
01348     if ((caster->path_denied&spell_ob->path_attuned) && !QUERY_FLAG(caster, FLAG_WIZ)) {
01349         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
01350                       "That spell path is denied to you.", NULL);
01351         return 0;
01352     }
01353 
01354     /* if it is a player casting the spell, and they are really casting it
01355      * (vs it coming from a wand, scroll, or whatever else), do some
01356      * checks.  We let monsters do special things - eg, they
01357      * don't need the skill, bypass level checks, etc. The monster function
01358      * should take care of that.
01359      * Remove the wiz check here and move it further down - some spells
01360      * need to have the right skill pointer passed, so we need to
01361      * at least process that code.
01362      */
01363     if (op->type == PLAYER && op == caster) {
01364         cast_level = caster_level(caster, spell_ob);
01365         if (spell_ob->skill) {
01366             skill = find_skill_by_name(op, spell_ob->skill);
01367             if (!skill) {
01368                 draw_ext_info_format(NDI_UNIQUE, 0, op,
01369                                      MSG_TYPE_SKILL, MSG_TYPE_SKILL_MISSING,
01370                                      "You need the skill %s to cast %s.",
01371                                      "You need the skill %s to cast %s.",
01372                                      spell_ob->skill, spell_ob->name);
01373                 return 0;
01374             }
01375             if (min_casting_level(op, spell_ob) > cast_level && !QUERY_FLAG(op, FLAG_WIZ)) {
01376                 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SKILL, MSG_TYPE_SKILL_FAILURE,
01377                               "You lack enough skill to cast that spell.", NULL);
01378                 return 0;
01379             }
01380         }
01381         /* If the caster is the wiz, they don't ever fail, and don't have
01382          * to have sufficient grace/mana.
01383          */
01384         if (!QUERY_FLAG(op, FLAG_WIZ)) {
01385             if (SP_level_spellpoint_cost(caster, spell_ob, SPELL_MANA)
01386             && SP_level_spellpoint_cost(caster, spell_ob, SPELL_MANA) >  op->stats.sp) {
01387                 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
01388                               "You don't have enough mana.", NULL);
01389                 return 0;
01390             }
01391             if (SP_level_spellpoint_cost(caster, spell_ob, SPELL_GRACE)
01392             && SP_level_spellpoint_cost(caster, spell_ob, SPELL_GRACE) > op->stats.grace) {
01393                 if (random_roll(0, op->stats.Wis-1, op, PREFER_HIGH)+op->stats.grace-10*SP_level_spellpoint_cost(caster, spell_ob, SPELL_GRACE)/op->stats.maxgrace > 0) {
01394                     draw_ext_info_format(NDI_UNIQUE, 0, op,
01395                                          MSG_TYPE_SPELL, MSG_TYPE_SPELL_INFO,
01396                                          "%s grants your prayer, though you are unworthy.",
01397                                          "%s grants your prayer, though you are unworthy.",
01398                                          godname);
01399                 } else {
01400                     prayer_failure(op, op->stats.grace, SP_level_spellpoint_cost(caster, spell_ob, SPELL_GRACE)-op->stats.grace);
01401                     draw_ext_info_format(NDI_UNIQUE, 0, op,
01402                                          MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01403                                          "%s ignores your prayer.",
01404                                          "%s ignores your prayer.",
01405                                          godname);
01406                     return 0;
01407                 }
01408             }
01409 
01410             /* player/monster is trying to cast the spell.  might fumble it */
01411             if (spell_ob->stats.grace
01412             && random_roll(0, 99, op, PREFER_HIGH) < (spell_ob->level/(float)MAX(1, op->level)*cleric_chance[op->stats.Wis])) {
01413                 play_sound_player_only(op->contr, SOUND_TYPE_SPELL, spell_ob, 0, "fumble");
01414                 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01415                               "You fumble the spell.", NULL);
01416                 if (settings.casting_time == TRUE) {
01417                     op->casting_time = -1;
01418                 }
01419                 op->stats.grace -= random_roll(1, SP_level_spellpoint_cost(caster, spell_ob, SPELL_GRACE), op, PREFER_LOW);
01420                 return 0;
01421             } else if (spell_ob->stats.sp) {
01422                 int failure = random_roll(0, 199, op, PREFER_HIGH)-op->contr->encumbrance+op->level-spell_ob->level+35;
01423 
01424                 if (failure < 0) {
01425                     draw_ext_info(NDI_UNIQUE, 0, op,
01426                                   MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01427                                   "You bungle the spell because you have too much heavy equipment in use.",
01428                                   NULL);
01429                     if (settings.spell_failure_effects == TRUE)
01430                         spell_failure(op, failure, SP_level_spellpoint_cost(caster, spell_ob, SPELL_MANA), skill);
01431                     op->contr->shoottype = old_shoottype;
01432                     op->stats.sp -= random_roll(0, SP_level_spellpoint_cost(caster, spell_ob, SPELL_MANA), op, PREFER_LOW);
01433                     return 0;
01434                 }
01435             }
01436         }
01437     }
01438 
01439     mflags = get_map_flags(op->map, NULL, op->x, op->y, NULL, NULL);
01440 
01441     /* See if we can cast a spell here.  If the caster and op are
01442      * not alive, then this would mean that the mapmaker put the
01443      * objects on the space - presume that they know what they are
01444      * doing.
01445      */
01446     if (spell_ob->type == SPELL
01447     && caster->type != POTION
01448     && !QUERY_FLAG(op, FLAG_WIZCAST)
01449     && (QUERY_FLAG(caster, FLAG_ALIVE) || QUERY_FLAG(op, FLAG_ALIVE))
01450     && !QUERY_FLAG(op, FLAG_MONSTER)
01451     && (((mflags&P_NO_MAGIC) && spell_ob->stats.sp) || ((mflags&P_NO_CLERIC) && spell_ob->stats.grace))) {
01452 
01453         if (op->type != PLAYER)
01454             return 0;
01455 
01456         if ((mflags&P_NO_CLERIC) && spell_ob->stats.grace)
01457             draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
01458                                  "This ground is unholy!  %s ignores you.",
01459                                  "This ground is unholy!  %s ignores you.",
01460                                  godname);
01461         else
01462             switch (op->contr->shoottype) {
01463             case range_magic:
01464                 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
01465                               "Something blocks your spellcasting.", NULL);
01466                 break;
01467 
01468             case range_misc:
01469                 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
01470                               "Something blocks the magic of your item.", NULL);
01471                 break;
01472             case range_golem:
01473                 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
01474                               "Something blocks the magic of your scroll.", NULL);
01475                 break;
01476 
01477             default:
01478                 break;
01479             }
01480         return 0;
01481     }
01482 
01483     if (caster == op && settings.casting_time == TRUE && spell_ob->type == SPELL) {
01484         if (op->casting_time == -1) { /* begin the casting */
01485             op->casting_time = spell_ob->casting_time*PATH_TIME_MULT(op, spell_ob);
01486             op->spell = spell_ob;
01487             /* put the stringarg into the object struct so that when the
01488             * spell is actually cast, it knows about the stringarg.
01489             * necessary for the invoke command spells.
01490             */
01491             if (stringarg) {
01492                 op->spellarg = strdup_local(stringarg);
01493             } else
01494                 op->spellarg = NULL;
01495             return 0;
01496         } else if (op->casting_time != 0) {
01497             if (op->type == PLAYER)
01498                 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_INFO,
01499                               "You are casting!", NULL);
01500             return 0;
01501         } else {    /* casting_time == 0 */
01502             op->casting_time = -1;
01503             spell_ob = op->spell;
01504             stringarg = op->spellarg;
01505         }
01506     } else {
01507         if (!QUERY_FLAG(caster, FLAG_WIZ)) {
01508             /* Take into account how long it takes to cast the spell.
01509              * if the player is casting it, then we use the time in
01510              * the spell object.  If it is a spell object, have it
01511              * take two ticks.  Things that cast spells on the players
01512              * behalf (eg, altars, and whatever else) shouldn't cost
01513              * the player any time.
01514              * Ignore casting time for firewalls
01515              */
01516             if (caster == op && caster->type != FIREWALL) {
01517                 op->speed_left -= spell_ob->casting_time*PATH_TIME_MULT(op, spell_ob)*FABS(op->speed);
01518                 /* Other portions of the code may also decrement the speed of the player, so
01519                  * put a lower limit so that the player isn't stuck here too long
01520                  */
01521                 if ((spell_ob->casting_time > 0)
01522                 && op->speed_left < -spell_ob->casting_time*PATH_TIME_MULT(op, spell_ob)*FABS(op->speed))
01523                     op->speed_left = -spell_ob->casting_time*PATH_TIME_MULT(op, spell_ob)*FABS(op->speed);
01524             } else if (caster->type == WAND
01525             || caster->type == HORN
01526             || caster->type == ROD
01527             || caster->type == POTION
01528             || caster->type == SCROLL) {
01529                 op->speed_left -= 2*FABS(op->speed);
01530             }
01531         }
01532     }
01533 
01534     if (op->type == PLAYER && op == caster && !QUERY_FLAG(caster, FLAG_WIZ)) {
01535         op->stats.grace -= SP_level_spellpoint_cost(caster, spell_ob, SPELL_GRACE);
01536         op->stats.sp -= SP_level_spellpoint_cost(caster, spell_ob, SPELL_MANA);
01537     }
01538 
01539     /* We want to try to find the skill to properly credit exp.
01540      * for spell casting objects, the exp goes to the skill the casting
01541      * object requires.
01542      */
01543     if (op != caster && !skill && caster->skill) {
01544         skill = find_skill_by_name(op, caster->skill);
01545         if (!skill) {
01546             char name[MAX_BUF];
01547 
01548             query_name(caster, name, MAX_BUF);
01549             draw_ext_info_format(NDI_UNIQUE, 0, op,
01550                                  MSG_TYPE_SKILL, MSG_TYPE_SKILL_MISSING,
01551                                  "You lack the skill %s to use the %s",
01552                                  "You lack the skill %s to use the %s",
01553                                  caster->skill, name);
01554             return 0;
01555         }
01556         change_skill(op, skill, 0);    /* needed for proper exp credit */
01557     }
01558 
01559     /* Need to get proper ownership for spells cast via runes - these are not
01560      * the normal 'rune of fire', but rather the magic runes that let the player
01561      * put some other spell into the rune (glyph, firetrap, magic rune, etc)
01562      */
01563     if (caster->type == RUNE) {
01564         object *owner = get_owner(caster);
01565 
01566         if (owner)
01567             skill = find_skill_by_name(owner, caster->skill);
01568     }
01569 
01570     if (confusion_effect) {
01571         /* If we get here, the confusion effect was 'random effect', so do it and bail out. */
01572         draw_ext_info_format(NDI_UNIQUE, 0, op,
01573                              MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01574                              "In your confused state, you can't control the magic!",
01575                              "In your confused state, you can't control the magic!");
01576         handle_spell_confusion(op);
01577         return 0;
01578     }
01579 
01580     play_sound_map(SOUND_TYPE_SPELL, caster, dir, spell_ob->name);
01581 
01582     switch (spell_ob->subtype) {
01583         /* The order of case statements is same as the order they show up
01584          * in in spells.h.
01585          */
01586     case SP_RAISE_DEAD:
01587         success = cast_raise_dead_spell(op, caster, spell_ob, dir, stringarg);
01588         break;
01589 
01590     case SP_RUNE:
01591         success = write_rune(op, caster, spell_ob, dir, stringarg);
01592         break;
01593 
01594     case SP_MAKE_MARK:
01595         success = write_mark(op, spell_ob, stringarg);
01596         break;
01597 
01598     case SP_BOLT:
01599         success = fire_bolt(op, caster, dir, spell_ob, skill);
01600         break;
01601 
01602     case SP_BULLET:
01603         success = fire_bullet(op, caster, dir, spell_ob);
01604         break;
01605 
01606     case SP_CONE:
01607         success = cast_cone(op, caster, dir, spell_ob);
01608         break;
01609 
01610     case SP_BOMB:
01611         success = create_bomb(op, caster, dir, spell_ob);
01612         break;
01613 
01614     case SP_WONDER:
01615         success = cast_wonder(op, caster, dir, spell_ob);
01616         break;
01617 
01618     case SP_SMITE:
01619         success = cast_smite_spell(op, caster, dir, spell_ob);
01620         break;
01621 
01622     case SP_MAGIC_MISSILE:
01623         success = fire_arch_from_position(op, caster, op->x+freearr_x[dir], op->y+freearr_y[dir], dir, spell_ob);
01624         break;
01625 
01626     case SP_SUMMON_GOLEM:
01627         success = summon_golem(op, caster, dir, spell_ob);
01628         old_shoottype = range_golem;
01629         break;
01630 
01631     case SP_DIMENSION_DOOR:
01632         /* dimension door needs the actual caster, because that is what is
01633          * moved.
01634          */
01635         success = dimension_door(op, caster, spell_ob, dir);
01636         break;
01637 
01638     case SP_MAGIC_MAPPING:
01639         if (op->type == PLAYER) {
01640             spell_effect(spell_ob, op->x, op->y, op->map, op);
01641             draw_magic_map(op);
01642             success = 1;
01643         } else
01644             success = 0;
01645         break;
01646 
01647     case SP_MAGIC_WALL:
01648         success = magic_wall(op, caster, dir, spell_ob);
01649         break;
01650 
01651     case SP_DESTRUCTION:
01652         success = cast_destruction(op, caster, spell_ob);
01653         break;
01654 
01655     case SP_PERCEIVE_SELF:
01656         success = perceive_self(op);
01657         break;
01658 
01659     case SP_WORD_OF_RECALL:
01660         success = cast_word_of_recall(op, caster, spell_ob);
01661         break;
01662 
01663     case SP_INVISIBLE:
01664         success = cast_invisible(op, caster, spell_ob);
01665         break;
01666 
01667     case SP_PROBE:
01668         success = probe(op, caster, spell_ob, dir);
01669         break;
01670 
01671     case SP_HEALING:
01672         success = cast_heal(op, caster, spell_ob, dir);
01673         break;
01674 
01675     case SP_CREATE_FOOD:
01676         success = cast_create_food(op, caster, spell_ob, dir, stringarg);
01677         break;
01678 
01679     case SP_EARTH_TO_DUST:
01680         success = cast_earth_to_dust(op, caster, spell_ob);
01681         break;
01682 
01683     case SP_CHANGE_ABILITY:
01684         success = cast_change_ability(op, caster, spell_ob, dir, 0);
01685         break;
01686 
01687     case SP_BLESS:
01688         success = cast_bless(op, caster, spell_ob, dir);
01689         break;
01690 
01691     case SP_CURSE:
01692         success = cast_curse(op, caster, spell_ob, dir);
01693         break;
01694 
01695     case SP_SUMMON_MONSTER:
01696         success = summon_object(op, caster, spell_ob, dir, stringarg);
01697         break;
01698 
01699     case SP_CHARGING:
01700         success = recharge(op, caster, spell_ob);
01701         break;
01702 
01703     case SP_POLYMORPH:
01704 #if 0
01705         /* Not great, but at least provide feedback so if players do have
01706          * polymorph (ie, find it as a preset item or left over from before
01707          * it was disabled), they get some feedback.
01708          */
01709         draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
01710                       "The spell fizzles", NULL);
01711         success = 0;
01712 #else
01713         success = cast_polymorph(op, caster, spell_ob, dir);
01714 #endif
01715         break;
01716 
01717     case SP_ALCHEMY:
01718         success = alchemy(op, caster, spell_ob);
01719         break;
01720 
01721     case SP_REMOVE_CURSE:
01722         success = remove_curse(op, caster, spell_ob);
01723         break;
01724 
01725     case SP_IDENTIFY:
01726         success = cast_identify(op, caster, spell_ob);
01727         break;
01728 
01729     case SP_DETECTION:
01730         success = cast_detection(op, caster, spell_ob);
01731         break;
01732 
01733     case SP_MOOD_CHANGE:
01734         success = mood_change(op, caster, spell_ob);
01735         break;
01736 
01737     case SP_MOVING_BALL:
01738         if (spell_ob->path_repelled
01739         && (spell_ob->path_repelled&caster->path_attuned) != spell_ob->path_repelled) {
01740             draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR,
01741                                  "You lack the proper attunement to cast %s",
01742                                  "You lack the proper attunement to cast %s",
01743                                  spell_ob->name);
01744             success = 0;
01745         } else
01746             success = fire_arch_from_position(op, caster, op->x+freearr_x[dir], op->y+freearr_y[dir], dir, spell_ob);
01747             break;
01748 
01749     case SP_SWARM:
01750         success = fire_swarm(op, caster, spell_ob, dir);
01751         break;
01752 
01753     case SP_CHANGE_MANA:
01754         success = cast_transfer(op, caster, spell_ob, dir);
01755         break;
01756 
01757     case SP_DISPEL_RUNE:
01758         /* in rune.c */
01759         success = dispel_rune(op, caster, spell_ob, skill, dir);
01760         break;
01761 
01762     case SP_CREATE_MISSILE:
01763         success = cast_create_missile(op, caster, spell_ob, dir, stringarg);
01764         break;
01765 
01766     case SP_CONSECRATE:
01767         success = cast_consecrate(op, caster, spell_ob);
01768         break;
01769 
01770     case SP_ANIMATE_WEAPON:
01771         success = animate_weapon(op, caster, spell_ob, dir);
01772         old_shoottype = range_golem;
01773         break;
01774 
01775     case SP_LIGHT:
01776         success = cast_light(op, caster, spell_ob, dir);
01777         break;
01778 
01779     case SP_CHANGE_MAP_LIGHT:
01780         success = cast_change_map_lightlevel(op, caster, spell_ob);
01781         break;
01782 
01783     case SP_FAERY_FIRE:
01784         success = cast_destruction(op, caster, spell_ob);
01785         break;
01786 
01787     case SP_CAUSE_DISEASE:
01788         success = cast_cause_disease(op, caster, spell_ob, dir);
01789         break;
01790 
01791     case SP_AURA:
01792         success = create_aura(op, caster, spell_ob);
01793         break;
01794 
01795     case SP_TOWN_PORTAL:
01796         success = cast_create_town_portal(op, caster, spell_ob, dir);
01797         break;
01798 
01799     case SP_ITEM_CURSE_BLESS:
01800         success = cast_item_curse_or_curse(op, caster, spell_ob);
01801         break;
01802 
01803     default:
01804         LOG(llevError, "cast_spell: Unhandled spell subtype %d\n", spell_ob->subtype);
01805     }
01806 
01807     /* FIXME - we need some better sound suppport */
01808     /* free the spell arg */
01809     if (settings.casting_time == TRUE && stringarg) {
01810         free(stringarg);
01811         stringarg = NULL;
01812     }
01813     /* perhaps a bit of a hack, but if using a wand, it has to change the skill
01814      * to something like use_magic_item, but you really want to be able to fire
01815      * it again.
01816      */
01817     if (op->contr)
01818         op->contr->shoottype = old_shoottype;
01819 
01820     return success;
01821 }
01822 
01829 void store_spell_expiry(object *spell) {
01830     /* Keep when to warn the player of expiration */
01831     char dur[10];
01832     int i = spell->duration/5;
01833 
01834     if (!i)
01835         i = 1;
01836     snprintf(dur, sizeof(dur), "%d", i);
01837     set_ob_key_value(spell, "spell_expiry_warn_1", dur, 1);
01838     i = i/5;
01839     if (i > 0) {
01840         snprintf(dur, sizeof(dur), "%d", i);
01841         set_ob_key_value(spell, "spell_expiry_warn_2", dur, 1);
01842     }
01843 }
01844 
01854 void check_spell_expiry(object *spell) {
01855     const char *key;
01856 
01857     if (!spell->env || !spell->env->type == PLAYER)
01858         return;
01859 
01860     if ((key = get_ob_key_value(spell, "spell_expiry_warn_1")) != NULL) {
01861         if (spell->duration == atoi(key)) {
01862             draw_ext_info_format(NDI_UNIQUE|NDI_NAVY, 0, spell->env, MSG_TYPE_SPELL, MSG_TYPE_SPELL_INFO,
01863                                  "The effects of your %s are draining out.", NULL, spell->name);
01864             return;
01865         }
01866     }
01867     if ((key = get_ob_key_value(spell, "spell_expiry_warn_2")) != NULL) {
01868         if (spell->duration == atoi(key)) {
01869             draw_ext_info_format(NDI_UNIQUE|NDI_NAVY, 0, spell->env, MSG_TYPE_SPELL, MSG_TYPE_SPELL_INFO,
01870                                  "The effects of your %s are about to expire.", NULL, spell->name);
01871             return;
01872         }
01873     }
01874 }