Atrinik Server 2.5
server/spell_effect.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00030 #include <global.h>
00031 
00037 void cast_magic_storm(object *op, object *tmp, int lvl)
00038 {
00039     /* Error */
00040     if (!tmp)
00041     {
00042         return;
00043     }
00044 
00045     tmp->level = SK_level(op);
00046     tmp->x = op->x;
00047     tmp->y = op->y;
00048 
00049     /* increase the area of destruction */
00050     tmp->stats.hp += lvl / 5;
00051     /* nasty recoils! */
00052     tmp->stats.dam = lvl;
00053     tmp->stats.maxhp = tmp->count;
00054     insert_ob_in_map(tmp, op->map, op, 0);
00055 }
00056 
00062 int recharge(object *op)
00063 {
00064     object *wand = find_marked_object(op);
00065     int cap;
00066 
00067     if (wand == NULL || wand->type != WAND)
00068     {
00069         new_draw_info(0, COLOR_RED, op, "You need to mark the wand you want to recharge.");
00070         return 0;
00071     }
00072 
00073     if (wand->stats.sp < 0 || wand->stats.sp >= NROFREALSPELLS || !spells[wand->stats.sp].charges)
00074     {
00075         new_draw_info_format(0, COLOR_RED, op, "The %s cannot be recharged.", query_name(wand, NULL));
00076         return 0;
00077     }
00078 
00079     if (!(rndm(0, 6)))
00080     {
00081         new_draw_info_format(0, COLOR_WHITE, op, "The %s vibrates violently, then explodes!", query_name(wand, NULL));
00082         play_sound_map(op->map, CMD_SOUND_EFFECT, "explosion.ogg", op->x, op->y, 0, 0);
00083         esrv_del_item(CONTR(op), wand->count, wand->env);
00084         remove_ob(wand);
00085         return 1;
00086     }
00087 
00088     new_draw_info_format(0, COLOR_WHITE, op, "The %s glows with power.", query_name(wand, NULL));
00089 
00090     wand->stats.food += 12 + rndm(1, spells[wand->stats.sp].charges);
00091     cap = spells[wand->stats.sp].charges + 12;
00092 
00093     /* Place a cap on it. */
00094     if (wand->stats.food > cap)
00095     {
00096         wand->stats.food = cap;
00097     }
00098 
00099     if (wand->arch && QUERY_FLAG(&wand->arch->clone, FLAG_ANIMATE))
00100     {
00101         SET_FLAG(wand, FLAG_ANIMATE);
00102         wand->speed = wand->arch->clone.speed;
00103         update_ob_speed(wand);
00104     }
00105 
00106     return 1;
00107 }
00108 
00121 int cast_create_food(object *op, object *caster, int dir, const char *stringarg)
00122 {
00123     int food_value;
00124     archetype *at = NULL;
00125     object *new_op;
00126 
00127     food_value = 50 * SP_level_dam_adjust(caster, SP_CREATE_FOOD, -1, 0);
00128 
00129     if (stringarg)
00130     {
00131         at = find_archetype(stringarg);
00132 
00133         if (at == NULL || ((at->clone.type != FOOD && at->clone.type != DRINK) || (at->clone.stats.food > food_value)))
00134         {
00135             stringarg = NULL;
00136         }
00137     }
00138 
00139     if (!stringarg)
00140     {
00141         archetype *at_tmp;
00142 
00143         /* We try to find the archetype with the maximum food value.
00144          * This removes the dependency of hard coded food values in this
00145          * function, and addition of new food types is automatically added.
00146          * We don't use flesh types because the weight values of those need
00147          * to be altered from the donor. */
00148 
00149         /* We assume the food items don't have multiple parts */
00150         for (at_tmp = first_archetype; at_tmp != NULL; at_tmp = at_tmp->next)
00151         {
00152             if (at_tmp->clone.type == FOOD || at_tmp->clone.type == DRINK)
00153             {
00154                 /* Basically, if the food value is something that is creatable
00155                  * under the limits of the spell and it is higher than
00156                  * the item we have now, take it instead. */
00157                 if (at_tmp->clone.stats.food <= food_value && (!at || at_tmp->clone.stats.food > at->clone.stats.food))
00158                 {
00159                     at = at_tmp;
00160                 }
00161             }
00162         }
00163     }
00164 
00165     /* Pretty unlikely (there are some very low food items), but you
00166      * never know */
00167     if (!at)
00168     {
00169         new_draw_info(0, COLOR_WHITE, op, "You don't have enough experience to create any food.");
00170         return 0;
00171     }
00172 
00173     food_value /= at->clone.stats.food;
00174     new_op = get_object();
00175     copy_object(&at->clone, new_op, 0);
00176     new_op->nrof = food_value;
00177 
00178     new_op->value = 0;
00179     SET_FLAG(new_op, FLAG_STARTEQUIP);
00180     SET_FLAG(new_op, FLAG_IDENTIFIED);
00181 
00182     if (new_op->nrof < 1)
00183     {
00184         new_op->nrof = 1;
00185     }
00186 
00187     cast_create_obj(op, new_op, dir);
00188     return 1;
00189 }
00190 
00196 int probe(object *op)
00197 {
00198     object *tmp;
00199 
00200     for (tmp = get_map_ob(op->map, op->x, op->y); tmp != NULL; tmp = tmp->above)
00201     {
00202         if (IS_LIVE(tmp))
00203         {
00204             if (op->owner && op->owner->type == PLAYER)
00205             {
00206                 new_draw_info_format(0, COLOR_WHITE, op->owner, "Your probe analyzes %s.", tmp->name);
00207 
00208                 if (tmp->head != NULL)
00209                 {
00210                     tmp = tmp->head;
00211                 }
00212 
00213                 examine(op->owner, tmp);
00214                 return 1;
00215             }
00216         }
00217     }
00218 
00219     return 0;
00220 }
00221 
00230 int cast_wor(object *op, object *caster)
00231 {
00232     object *dummy;
00233 
00234     if (op->type != PLAYER)
00235     {
00236         return 0;
00237     }
00238 
00239     if (blocks_magic(op->map, op->x, op->y))
00240     {
00241         new_draw_info(0, COLOR_WHITE, op, "Something blocks your spell.");
00242         return 0;
00243     }
00244 
00245     dummy = get_archetype("force");
00246 
00247     if (dummy == NULL)
00248     {
00249         LOG(llevBug, "cast_wor(): get_archetype failed (%s - %s)!\n", query_name(op, NULL), query_name(caster, NULL));
00250         return 0;
00251     }
00252 
00253     /* Better insert the spell in the player */
00254     if (op->owner)
00255     {
00256         op = op->owner;
00257     }
00258 
00259     dummy->speed = 0.002f * ((float) (spells[SP_WOR].bdur + SP_level_strength_adjust(caster, SP_WOR)));
00260     update_ob_speed(dummy);
00261     dummy->speed_left = -1;
00262     dummy->type = WORD_OF_RECALL;
00263 
00264     FREE_AND_COPY_HASH(EXIT_PATH(dummy), CONTR(op)->savebed_map);
00265     EXIT_X(dummy) = CONTR(op)->bed_x;
00266     EXIT_Y(dummy) = CONTR(op)->bed_y;
00267 
00268     insert_ob_in_ob(dummy, op);
00269     new_draw_info(0, COLOR_WHITE, op, "You feel a force starting to build up inside you.");
00270 
00271     return 1;
00272 }
00273 
00286 int cast_create_town_portal(object *op)
00287 {
00288     object *dummy, *force, *old_force, *current_obj;
00289     archetype *perm_portal;
00290     char portal_name[1024], portal_message[1024];
00291     const char *exitpath = NULL;
00292     sint16 exitx = 15, exity = 15;
00293     mapstruct *exitmap = NULL;
00294     int op_level;
00295 
00296     /* The first thing to do is to check if we have a marked destination
00297      * dummy is used to make a check inventory for the force */
00298     if (!strncmp(op->map->path, settings.localdir, strlen(settings.localdir)))
00299     {
00300         new_draw_info(0, COLOR_NAVY, op, "You can't cast that here.\n");
00301         return 0;
00302     }
00303 
00304     dummy = get_archetype("force");
00305 
00306     if (!dummy)
00307     {
00308         LOG(llevBug, "cast_create_town_portal(): get_archetype failed (force) for %s!\n", op->name);
00309         return 0;
00310     }
00311 
00312     FREE_AND_ADD_REF_HASH(dummy->slaying, shstr_cons.portal_destination_name);
00313     dummy->stats.sp = 1;
00314     force = check_inv_recursive(op, dummy);
00315 
00316     /* Here we know there is no destination marked up.
00317      * We have 2 things to do:
00318      * 1. Mark the destination in the player inventory.
00319      * 2. Let the player know it worked. */
00320     if (force == NULL)
00321     {
00322         FREE_AND_ADD_REF_HASH(dummy->name, op->map->path);
00323         FREE_AND_ADD_REF_HASH(dummy->race, op->map->path);
00324         EXIT_X(dummy) = op->x;
00325         EXIT_Y(dummy) = op->y;
00326         dummy->speed = 0.0;
00327         update_ob_speed(dummy);
00328         insert_ob_in_ob(dummy, op);
00329         new_draw_info(0, COLOR_NAVY, op, "You fix this place in your mind.\nYou feel you are able to come here from anywhere.");
00330         return 1;
00331     }
00332 
00333     /* Here we know where the town portal should go to
00334      * We should kill any existing portal associated with the player.
00335      * Than we should create the 2 portals.
00336      * For each of them, we need:
00337      *    - To create the portal with the name of the player+destination map
00338      *    - set the owner of the town portal
00339      *    - To mark the position of the portal in the player's inventory
00340      *      for easier destruction.
00341      *
00342      * The mark works has follow:
00343      *   slaying: Existing town portal
00344      *   hp, sp : x & y of the associated portal
00345      *   name   : name of the portal
00346      *   race   : map the portal is in */
00347 
00348     /* First step: killing existing town portals */
00349     dummy = get_archetype("force");
00350 
00351     if (dummy == NULL)
00352     {
00353         LOG(llevBug, "cast_create_town_portal(): get_archetype failed (force) for %s!\n", query_name(op, NULL));
00354         return 0;
00355     }
00356 
00357     /* Useful for string comparison later */
00358     FREE_AND_COPY_HASH(dummy->name, portal_name);
00359     FREE_AND_ADD_REF_HASH(dummy->slaying, shstr_cons.portal_active_name);
00360     dummy->stats.sp = 1;
00361     perm_portal = spellarch[SP_TOWN_PORTAL];
00362 
00363     /* To kill a town portal, we go trough the player's inventory,
00364      * for each marked portal in player's inventory,
00365      *   -We try load the associated map (if impossible, consider the portal destructed)
00366      *   -We find any portal in the specified location.
00367      *      If it has the good name, we destruct it.
00368      *   -We destruct the force indicating that portal. */
00369     while ((old_force = check_inv_recursive(op, dummy)))
00370     {
00371         FREE_AND_ADD_REF_HASH(exitpath, !strstr(old_force->name, op->name) ? old_force->name : old_force->race);
00372         exitx = EXIT_X(old_force);
00373         exity = EXIT_Y(old_force);
00374 
00375         if (!strncmp(exitpath, settings.localdir, strlen(settings.localdir)))
00376         {
00377             exitmap = ready_map_name(exitpath, MAP_PLAYER_UNIQUE);
00378         }
00379         else
00380         {
00381             exitmap = ready_map_name(exitpath, 0);
00382         }
00383 
00384         if (exitmap)
00385         {
00386             current_obj = present_arch(perm_portal, exitmap, exitx, exity);
00387 
00388             while (current_obj)
00389             {
00390                 if (strcmp(current_obj->name, strstr(old_force->name, op->name) ? old_force->name : old_force->race) == 0)
00391                 {
00392                     if (!QUERY_FLAG(current_obj, FLAG_REMOVED))
00393                     {
00394                         remove_ob(current_obj);
00395                     }
00396 
00397                     break;
00398                 }
00399                 else
00400                 {
00401                     current_obj = current_obj->above;
00402                 }
00403             }
00404         }
00405 
00406         if (!QUERY_FLAG(old_force, FLAG_REMOVED))
00407         {
00408             remove_ob(old_force);
00409         }
00410 
00411         FREE_AND_CLEAR_HASH2(exitpath);
00412     }
00413 
00414     /* Creating the portals.
00415      * The very first thing to do is to ensure
00416      * access to the destination map.
00417      * If we can't, don't fizzle. Simply warn player.
00418      * This ensure player pays his mana for the spell
00419      * because HE is responsible of forgotting. */
00420     op_level = SK_level(op);
00421 
00422     if (op_level < 15)
00423     {
00424         snprintf(portal_message, sizeof(portal_message), "Air moves around you and a huge smell of ammoniac rounds you as you pass through %s's portal.\nPouah!", op->name);
00425     }
00426     else if (op_level < 30)
00427     {
00428         snprintf(portal_message, sizeof(portal_message), "%s's portal smells ozone.\nYou do a lot of movements and finally pass through the small hole in the air.", op->name);
00429     }
00430     else if (op_level < 60)
00431     {
00432         snprintf(portal_message, sizeof(portal_message), "A sort of door opens in the air in front of you, showing you the path to somewhere else.");
00433     }
00434     else
00435     {
00436         snprintf(portal_message, sizeof(portal_message), "As you walk on %s's portal, flowers come from the ground around you.\nYou feel quiet.", op->name);
00437     }
00438 
00439     FREE_AND_CLEAR_HASH(exitpath);
00440 
00441     /* we want ensure that the force->name is still in hash table */
00442     if (!strstr(force->name, op->name))
00443     {
00444         FREE_AND_ADD_REF_HASH(exitpath, force->name);
00445     }
00446     else
00447     {
00448         FREE_AND_ADD_REF_HASH(exitpath, force->race);
00449     }
00450 
00451     exitx = EXIT_X(force);
00452     exity = EXIT_Y(force);
00453 
00454     /* Delete the force inside the player */
00455     if (!QUERY_FLAG(force, FLAG_REMOVED))
00456     {
00457         remove_ob(force);
00458     }
00459 
00460     /* Ensure exit map is loaded */
00461     if (!strncmp(exitpath, settings.localdir, strlen(settings.localdir)))
00462     {
00463         exitmap = ready_map_name(exitpath, MAP_PLAYER_UNIQUE);
00464     }
00465     else
00466     {
00467         exitmap = ready_map_name(exitpath, 0);
00468     }
00469 
00470     /* If we were unable to load (ex. random map deleted), warn player */
00471     if (exitmap == NULL)
00472     {
00473         new_draw_info(0, COLOR_NAVY, op, "Something strange happened.\nYou can't remember where to go?!");
00474         FREE_AND_CLEAR_HASH(exitpath);
00475         return 1;
00476     }
00477 
00478     /* Create a portal in front of player dummy contain the portal and
00479      * force contain the track to kill it later. */
00480     snprintf(portal_name, sizeof(portal_name), "%s's portal to %s", op->name, exitpath);
00481     /* The portal */
00482     dummy = arch_to_object(spellarch[SP_TOWN_PORTAL]);
00483 
00484     if (dummy == NULL)
00485     {
00486         LOG(llevBug, "cast_create_town_portal(): arch_to_object failed (perm_magic_portal) for %s!\n", query_name(op, NULL));
00487         FREE_AND_CLEAR_HASH(exitpath);
00488         return 0;
00489     }
00490 
00491     FREE_AND_ADD_REF_HASH(EXIT_PATH(dummy), exitpath);
00492     EXIT_X(dummy) = exitx;
00493     EXIT_Y(dummy) = exity;
00494     FREE_AND_COPY_HASH(dummy->name, portal_name);
00495     FREE_AND_COPY_HASH(dummy->msg, portal_message);
00496     CLEAR_FLAG(dummy, FLAG_WALK_ON);
00497     CLEAR_FLAG(dummy, FLAG_FLY_ON);
00498 
00499     /* Set as a 2 ways exit (see manual_apply & is_legal_2ways_exit funcs) */
00500     dummy->stats.exp = 1;
00501     /* Save the owner of the portal */
00502     FREE_AND_COPY_HASH(dummy->race, op->name);
00503     cast_create_obj(op, dummy, 0);
00504 
00505     /* The force */
00506     force = get_archetype("force");
00507 
00508     if (force == NULL)
00509     {
00510         LOG(llevBug, "cast_create_town_portal(): get_archetype failed (force) for %s!\n", query_name(op, NULL));
00511         FREE_AND_CLEAR_HASH(exitpath);
00512         return 0;
00513     }
00514 
00515     FREE_AND_ADD_REF_HASH(force->slaying, shstr_cons.portal_active_name);
00516     FREE_AND_ADD_REF_HASH(force->race, op->map->path);
00517     FREE_AND_COPY_HASH(force->name, portal_name);
00518     EXIT_X(force) = dummy->x;
00519     EXIT_Y(force) = dummy->y;
00520     force->speed = 0.0;
00521     update_ob_speed(force);
00522     insert_ob_in_ob(force, op);
00523     /* Create a portal in the destination map
00524      * dummy contain the portal and
00525      * force the track to kill it later */
00526     snprintf(portal_name, sizeof(portal_name), "%s's portal to %s", op->name, op->map->path);
00527 
00528     /* The portal */
00529     dummy = arch_to_object(spellarch[SP_TOWN_PORTAL]);
00530 
00531     if (dummy == NULL)
00532     {
00533         LOG(llevBug, "cast_create_town_portal(): arch_to_object failed (perm_magic_portal) for %s!\n", query_name(op, NULL));
00534         FREE_AND_CLEAR_HASH(exitpath);
00535         return 0;
00536     }
00537 
00538     FREE_AND_ADD_REF_HASH(EXIT_PATH(dummy), op->map->path);
00539     EXIT_X(dummy) = op->x;
00540     EXIT_Y(dummy) = op->y;
00541     FREE_AND_COPY_HASH(dummy->name, portal_name);
00542     FREE_AND_COPY_HASH(dummy->msg, portal_message);
00543     CLEAR_FLAG(dummy, FLAG_WALK_ON);
00544     CLEAR_FLAG(dummy, FLAG_FLY_ON);
00545     dummy->x = exitx;
00546     dummy->y = exity;
00547 
00548     /* Set as a 2 ways exit (see manual_apply & is_legal_2ways_exit funcs) */
00549     dummy->stats.exp = 1;
00550     /* Save the owner of the portal */
00551     FREE_AND_COPY_HASH(dummy->race, op->name);
00552     insert_ob_in_map(dummy, exitmap, op, INS_NO_MERGE | INS_NO_WALK_ON);
00553     /* The force */
00554     force = get_archetype("force");
00555 
00556     if (force == NULL)
00557     {
00558         LOG(llevBug, "cast_create_town_portal(): get_archetype failed (force) for %s!\n", query_name(op, NULL));
00559         FREE_AND_CLEAR_HASH(exitpath);
00560         return 0;
00561     }
00562 
00563     FREE_AND_ADD_REF_HASH(force->slaying, shstr_cons.portal_active_name);
00564     FREE_AND_ADD_REF_HASH(force->race, exitpath);
00565     FREE_AND_COPY_HASH(force->name, portal_name);
00566     EXIT_X(force) = dummy->x;
00567     EXIT_Y(force) = dummy->y;
00568     force->speed = 0.0;
00569     update_ob_speed(force);
00570     insert_ob_in_ob(force, op);
00571 
00572     /* Describe the player what happened */
00573     new_draw_info(0, COLOR_NAVY, op, "You see air moving and showing you the way home.");
00574     FREE_AND_CLEAR_HASH(exitpath);
00575     return 1;
00576 }
00577 
00585 int cast_destruction(object *op, object *caster, int dam, int attacktype)
00586 {
00587     int i, j, range, xt, yt;
00588     object *tmp, *hitter;
00589     mapstruct *m;
00590 
00591     /* The hitter object. */
00592     hitter = arch_to_object(spellarch[SP_DESTRUCTION]);
00593     set_owner(hitter, op);
00594     hitter->level = SK_level(caster);
00595 
00596     /* Calculate maximum range of the spell */
00597     range = MAX(SP_level_strength_adjust(caster, SP_DESTRUCTION), spells[SP_DESTRUCTION].bdur);
00598     dam += SP_level_dam_adjust(caster, SP_DESTRUCTION, -1, 0);
00599 
00600     for (i = -range; i <= range; i++)
00601     {
00602         for (j = -range; j <= range; j++)
00603         {
00604             xt = op->x + i;
00605             yt = op->y + j;
00606 
00607             if (!(m = get_map_from_coord(op->map, &xt, &yt)))
00608             {
00609                 continue;
00610             }
00611 
00612             /* Nothing alive here? Move on... */
00613             if (!(GET_MAP_FLAGS(m, xt, yt) & (P_IS_ALIVE | P_IS_PLAYER)))
00614             {
00615                 continue;
00616             }
00617 
00618             /* Try to get an object to hit */
00619             for (tmp = GET_MAP_OB(m, xt, yt); tmp; tmp = tmp->above)
00620             {
00621                 /* Get head. */
00622                 if (tmp->head)
00623                 {
00624                     tmp = tmp->head;
00625                 }
00626 
00627                 /* Skip the caster and not alive objects. */
00628                 if (tmp == caster || !IS_LIVE(tmp) || spell_attack_missed(hitter, tmp))
00629                 {
00630                     continue;
00631                 }
00632 
00633                 if (!is_friend_of(op, tmp))
00634                 {
00635                     sint16 damage = dam;
00636 
00637                     if (tmp->quick_pos)
00638                     {
00639                         damage /= (tmp->quick_pos >> 4) + 1;
00640                     }
00641 
00642                     hit_player(tmp, damage, hitter, attacktype);
00643                     break;
00644                 }
00645             }
00646         }
00647     }
00648 
00649     return 1;
00650 }
00651 
00658 int cast_heal_around(object *op, int level, int type)
00659 {
00660     int success = 0;
00661 
00662     switch (type)
00663     {
00664         case SP_RAIN_HEAL:
00665         {
00666             int i, x, y;
00667             mapstruct *m;
00668             object *tmp;
00669 
00670             for (i = 0; i <= SIZEOFFREE1; i++)
00671             {
00672                 x = op->x + freearr_x[i];
00673                 y = op->y + freearr_y[i];
00674 
00675                 if (!(m = get_map_from_coord(op->map, &x, &y)))
00676                 {
00677                     continue;
00678                 }
00679 
00680                 if (!(GET_MAP_FLAGS(m, x, y) & (P_IS_ALIVE | P_IS_PLAYER)))
00681                 {
00682                     continue;
00683                 }
00684 
00685                 for (tmp = GET_MAP_OB_LAYER(m, x, y, LAYER_LIVING - 1); tmp && tmp->layer == LAYER_LIVING; tmp = tmp->above)
00686                 {
00687                     tmp = HEAD(tmp);
00688 
00689                     if (tmp == op || !IS_LIVE(tmp) || !is_friend_of(op, tmp))
00690                     {
00691                         continue;
00692                     }
00693 
00694                     cast_heal(op, level, tmp, SP_MINOR_HEAL);
00695                     success = 1;
00696                 }
00697             }
00698 
00699             break;
00700         }
00701 
00702         case SP_PARTY_HEAL:
00703         {
00704             objectlink *ol;
00705 
00706             if (op->type != PLAYER)
00707             {
00708                 return 0;
00709             }
00710             else if (!CONTR(op)->party)
00711             {
00712                 new_draw_info(0, COLOR_WHITE, op, "You need to be in a party to cast this spell.");
00713                 return 0;
00714             }
00715 
00716             for (ol = CONTR(op)->party->members; ol; ol = ol->next)
00717             {
00718                 if (on_same_map(ol->objlink.ob, op))
00719                 {
00720                     cast_heal(op, level, ol->objlink.ob, SP_MINOR_HEAL);
00721                 }
00722             }
00723 
00724             success = 1;
00725             break;
00726         }
00727     }
00728 
00729     return success;
00730 }
00731 
00738 int cast_heal(object *op, int level, object *target, int spell_type)
00739 {
00740     archetype *at;
00741     object *temp;
00742     int heal = 0, success = 0;
00743 
00744     if (!op || !target)
00745     {
00746         LOG(llevBug, "cast_heal(): target or caster NULL (op: %s target: %s)\n", query_name(op, NULL), query_name(target, NULL));
00747         return 0;
00748     }
00749 
00750     switch (spell_type)
00751     {
00752         case SP_CURE_DISEASE:
00753             if (cure_disease(target, op))
00754             {
00755                 success = 1;
00756             }
00757 
00758             break;
00759 
00760         case SP_CURE_POISON:
00761             at = find_archetype("poisoning");
00762 
00763             if (op != target && target->type == PLAYER)
00764             {
00765                 new_draw_info_format(0, COLOR_WHITE, target, "%s casts cure poison on you!", op->name ? op->name : "Someone");
00766             }
00767 
00768             if (op != target && op->type == PLAYER)
00769             {
00770                 new_draw_info_format(0, COLOR_WHITE, op, "You cast cure poison on %s!", target->name ? target->name : "someone");
00771             }
00772 
00773             for (temp = target->inv; temp != NULL; temp = temp->below)
00774             {
00775                 if (temp->arch == at)
00776                 {
00777                     success = 1;
00778                     temp->stats.food = 1;
00779                 }
00780             }
00781 
00782             if (success)
00783             {
00784                 if (target->type == PLAYER)
00785                 {
00786                     new_draw_info(0, COLOR_WHITE, target, "Your body feels cleansed.");
00787                 }
00788 
00789                 if (op != target && op->type == PLAYER)
00790                 {
00791                     new_draw_info_format(0, COLOR_WHITE, op, "%s's body seems cleansed.", target->name ? target->name : "Someone");
00792                 }
00793             }
00794             else
00795             {
00796                 if (target->type == PLAYER)
00797                 {
00798                     new_draw_info(0, COLOR_WHITE, target, "You are not poisoned.");
00799                 }
00800 
00801                 if (op != target && op->type == PLAYER)
00802                 {
00803                     new_draw_info_format(0, COLOR_WHITE, op, "%s is not poisoned.", target->name ? target->name : "Someone");
00804                 }
00805             }
00806 
00807             break;
00808 
00809         case SP_CURE_CONFUSION:
00810             at = find_archetype("confusion");
00811 
00812             if (op != target && target->type == PLAYER)
00813             {
00814                 new_draw_info_format(0, COLOR_WHITE, target, "%s casts cure confusion on you!", op->name ? op->name : "Someone");
00815             }
00816 
00817             if (op != target && op->type == PLAYER)
00818             {
00819                 new_draw_info_format(0, COLOR_WHITE, op, "You cast cure confusion on %s!", target->name ? target->name : "someone");
00820             }
00821 
00822             for (temp = target->inv; temp != NULL; temp = temp->below)
00823             {
00824                 if (temp->arch == at)
00825                 {
00826                     success = 1;
00827                     temp->stats.food = 1;
00828                 }
00829             }
00830 
00831             if (success)
00832             {
00833                 if (target->type == PLAYER)
00834                 {
00835                     new_draw_info(0, COLOR_WHITE, target, "Your mind feels clearer.");
00836                 }
00837 
00838                 if (op != target && op->type == PLAYER)
00839                 {
00840                     new_draw_info_format(0, COLOR_WHITE, op, "%s's mind seems clearer.", target->name ? target->name : "Someone");
00841                 }
00842             }
00843             else
00844             {
00845                 if (target->type == PLAYER)
00846                 {
00847                     new_draw_info(0, COLOR_WHITE, target, "You are not confused.");
00848                 }
00849 
00850                 if (op != target && op->type == PLAYER)
00851                 {
00852                     new_draw_info_format(0, COLOR_WHITE, op, "%s is not confused.", target->name ? target->name : "Someone");
00853                 }
00854             }
00855 
00856             break;
00857 
00858         case SP_MINOR_HEAL:
00859             success = 1;
00860             heal = rndm(2, 5 + level) + 6;
00861 
00862             if (op->type == PLAYER)
00863             {
00864                 if (heal > 0)
00865                 {
00866                     new_draw_info_format(0, COLOR_WHITE, op, "The prayer heals %s for %d hp!", op == target ? "you" : (target ? target->name : "NULL"), heal);
00867                 }
00868                 else
00869                 {
00870                     new_draw_info(0, COLOR_WHITE, op, "The healing prayer fails!");
00871                 }
00872             }
00873 
00874             if (op != target && target->type == PLAYER)
00875             {
00876                 if (heal > 0)
00877                 {
00878                     new_draw_info_format(0, COLOR_WHITE, target, "%s casts minor healing on you healing %d hp!", op->name, heal);
00879                 }
00880                 else
00881                 {
00882                     new_draw_info_format(0, COLOR_WHITE, target, "%s casts minor healing on you but it fails!", op->name);
00883                 }
00884             }
00885 
00886             break;
00887 
00888         case SP_GREATER_HEAL:
00889             success = 1;
00890             heal = rndm(4, 5 + level) + rndm(4, 5 + level) + 12;
00891 
00892             if (op->type == PLAYER)
00893             {
00894                 if (heal > 0)
00895                 {
00896                     new_draw_info_format(0, COLOR_WHITE, op, "The prayer heals %s for %d hp!", op == target ? "you" : (target ? target->name : "NULL"), heal);
00897                 }
00898                 else
00899                 {
00900                     new_draw_info(0, COLOR_WHITE, op, "The healing prayer fails!");
00901                 }
00902             }
00903 
00904             if (op != target && target->type == PLAYER)
00905             {
00906                 if (heal > 0)
00907                 {
00908                     new_draw_info_format(0, COLOR_WHITE, target, "%s casts greater healing on you healing %d hp!", op->name, heal);
00909                 }
00910                 else
00911                 {
00912                     new_draw_info_format(0, COLOR_WHITE, target, "%s casts greater healing on you but it fails!", op->name);
00913                 }
00914             }
00915 
00916             break;
00917 
00918         case SP_RESTORATION:
00919             if (cast_heal(op, level, target, SP_CURE_POISON))
00920             {
00921                 success = 1;
00922             }
00923 
00924             if (cast_heal(op, level, target, SP_CURE_CONFUSION))
00925             {
00926                 success = 1;
00927             }
00928 
00929             if (cast_heal(op, level, target, SP_CURE_DISEASE))
00930             {
00931                 success = 1;
00932             }
00933 
00934             if (target->stats.food < 999)
00935             {
00936                 success = 1;
00937                 target->stats.food = 999;
00938             }
00939 
00940             if (cast_heal(op, level, target, SP_MINOR_HEAL))
00941             {
00942                 success = 1;
00943             }
00944 
00945             return success;
00946     }
00947 
00948     if (heal > 0)
00949     {
00950         if (reduce_symptoms(target, heal))
00951         {
00952             success = 1;
00953         }
00954 
00955         if (target->stats.hp < target->stats.maxhp)
00956         {
00957             if (target == op)
00958             {
00959                 if (op->type == PLAYER)
00960                 {
00961                     CONTR(op)->stat_damage_healed += MIN(heal, target->stats.maxhp - target->stats.hp);
00962                 }
00963             }
00964             else
00965             {
00966                 if (op->type == PLAYER)
00967                 {
00968                     CONTR(op)->stat_damage_healed_other += MIN(heal, target->stats.maxhp - target->stats.hp);
00969                 }
00970 
00971                 if (target->type == PLAYER)
00972                 {
00973                     CONTR(target)->stat_damage_heal_received += MIN(heal, target->stats.maxhp - target->stats.hp);
00974                 }
00975             }
00976 
00977             success = 1;
00978             target->stats.hp += heal;
00979 
00980             if (target->stats.hp > target->stats.maxhp)
00981             {
00982                 target->stats.hp = target->stats.maxhp;
00983             }
00984         }
00985 
00986         if (target->damage_round_tag != ROUND_TAG)
00987         {
00988             target->last_damage = 0;
00989             target->damage_round_tag = ROUND_TAG;
00990         }
00991 
00992         target->last_damage -= heal;
00993     }
00994 
00995     if (success)
00996     {
00997         op->speed_left = -FABS(op->speed) * 3;
00998     }
00999 
01000     if (insert_spell_effect(spells[spell_type].archname, target->map, target->x, target->y))
01001     {
01002         LOG(llevDebug, "insert_spell_effect() failed: spell:%d, obj:%s target:%s\n", spell_type, query_name(op, NULL), query_name(target, NULL));
01003     }
01004 
01005     return success;
01006 }
01007 
01016 int cast_change_attr(object *op, object *caster, object *target, int spell_type)
01017 {
01018     object *tmp = target, *tmp2 = NULL, *force = NULL;
01019     int is_refresh = 0, msg_flag = 1, i = 0;
01020 
01021     if (tmp == NULL)
01022     {
01023         return 0;
01024     }
01025 
01026     /* We ID the buff force with spell_type... if we find one, we have
01027      * old effect. If not, we create a fresh force. */
01028     for (tmp2 = tmp->inv; tmp2 != NULL; tmp2 = tmp2->below)
01029     {
01030         if (tmp2->type == FORCE)
01031         {
01032             if (tmp2->value == spell_type)
01033             {
01034                 /* The old effect will be "refreshed" */
01035                 force = tmp2;
01036                 is_refresh = 1;
01037                 new_draw_info(0, COLOR_WHITE, op, "You recast the spell while in effect.");
01038             }
01039         }
01040     }
01041 
01042     if (force == NULL)
01043     {
01044         force = get_archetype("force");
01045     }
01046 
01047     /* Mark this force with the originating spell */
01048     force->value = spell_type;
01049 
01050     switch (spell_type)
01051     {
01052         case SP_STRENGTH:
01053             force->speed_left = -1;
01054 
01055             if (tmp->type != PLAYER)
01056             {
01057                 if (op->type == PLAYER)
01058                 {
01059                     new_draw_info(0, COLOR_WHITE, op, "You can't cast this kind of spell on your target.");
01060                 }
01061 
01062                 return 0;
01063             }
01064             else if (op->type == PLAYER && op != tmp)
01065             {
01066                 new_draw_info_format(0, COLOR_WHITE, tmp, "%s casts strength on you!", op->name ? op->name : "Someone");
01067             }
01068 
01069             if (force->stats.Str < 2)
01070             {
01071                 force->stats.Str++;
01072 
01073                 if (op->type == PLAYER && op != tmp)
01074                 {
01075                     new_draw_info_format(0, COLOR_WHITE, op, "%s gets stronger.", tmp->name ? tmp->name : "Someone");
01076                 }
01077             }
01078             else
01079             {
01080                 msg_flag = 0;
01081                 new_draw_info(0, COLOR_WHITE, tmp, "You don't grow stronger but the spell is refreshed.");
01082 
01083                 if (op->type == PLAYER && op != tmp)
01084                 {
01085                     new_draw_info_format(0, COLOR_WHITE, op, "%s doesn't grow stronger but the spell is refreshed.", tmp->name ? tmp->name : "Someone");
01086                 }
01087             }
01088 
01089             if (insert_spell_effect(spells[SP_STRENGTH].archname, target->map, target->x, target->y))
01090             {
01091                 LOG(llevDebug, "insert_spell_effect() failed: spell:%d, obj:%s caster:%s target:%s\n", spell_type, query_name(op, NULL), query_name(caster, NULL), query_name(target, NULL));
01092             }
01093 
01094             break;
01095 
01096         /* Attacktype protection spells */
01097         case SP_PROT_COLD:
01098             i = ATNR_COLD;
01099             break;
01100 
01101         case SP_PROT_FIRE:
01102             i = ATNR_FIRE;
01103             break;
01104 
01105         case SP_PROT_ELEC:
01106             i = ATNR_ELECTRICITY;
01107             break;
01108 
01109         case SP_PROT_POISON:
01110             i = ATNR_POISON;
01111             break;
01112     }
01113 
01114     if (i)
01115     {
01116         new_draw_info_format(0, COLOR_WHITE, op, "Your protection to %s grows.", attack_name[i]);
01117         force->protection[i] = MIN(SP_level_dam_adjust(caster, spell_type, -1, 0), 50);
01118     }
01119 
01120     force->speed_left = -1 - SP_level_strength_adjust(caster, spell_type) * 0.1f;
01121 
01122     if (!is_refresh)
01123     {
01124         SET_FLAG(force, FLAG_APPLIED);
01125         force = insert_ob_in_ob(force, tmp);
01126     }
01127 
01128     if (msg_flag)
01129     {
01130         /* Mostly to display any messages */
01131         change_abil(tmp, force);
01132         /* This takes care of some stuff that change_abil() */
01133         fix_player(tmp);
01134     }
01135 
01136     return 1;
01137 }
01138 
01147 int create_bomb(object *op, object *caster, int dir, int spell_type)
01148 {
01149     object *tmp;
01150     int dx = op->x + freearr_x[dir], dy = op->y + freearr_y[dir];
01151 
01152     if (wall(op->map, dx, dy))
01153     {
01154         new_draw_info(0, COLOR_WHITE, op, "There is something in the way.");
01155         return 0;
01156     }
01157 
01158     tmp = arch_to_object(spellarch[spell_type]);
01159 
01160     /* level dependencies for bomb  */
01161     tmp->stats.dam = SP_level_dam_adjust(caster, spell_type, -1, 0);
01162     tmp->stats.hp = spells[spell_type].bdur + SP_level_strength_adjust(caster, spell_type);
01163     tmp->level = SK_level(caster);
01164     set_owner(tmp,op);
01165     tmp->x = dx, tmp->y = dy;
01166     insert_ob_in_map(tmp, op->map, op, 0);
01167 
01168     return 1;
01169 }
01170 
01174 void animate_bomb(object *op)
01175 {
01176     int i;
01177     archetype *at;
01178 
01179     if (!op->map)
01180     {
01181         return;
01182     }
01183 
01184     if (op->state != NUM_ANIMATIONS(op) - 1)
01185     {
01186         op->state++;
01187         SET_ANIMATION(op, op->state);
01188         return;
01189     }
01190 
01191     at = find_archetype("splint");
01192 
01193     if (at)
01194     {
01195         for (i = 1; i < 9; i++)
01196         {
01197             fire_arch_from_position(op, op, op->x, op->y, i, at, 0, NULL);
01198         }
01199     }
01200 
01201     explode_object(op);
01202 }
01203 
01210 int remove_depletion(object *op, object *target)
01211 {
01212     archetype *at;
01213     object *depl;
01214     int i, success = 0;
01215 
01216     if ((at = find_archetype("depletion")) == NULL)
01217     {
01218         LOG(llevBug, "Could not find archetype depletion");
01219         return 0;
01220     }
01221 
01222     if (!op || !target)
01223     {
01224         return 0;
01225     }
01226 
01227     if (target->type != PLAYER)
01228     {
01229         /* Fake messages for non player... */
01230         if (op->type == PLAYER)
01231         {
01232             new_draw_info_format(0, COLOR_WHITE, op, "You cast depletion on %s.", query_base_name(target, NULL));
01233             new_draw_info(0, COLOR_WHITE, op, "There is no depletion.");
01234         }
01235 
01236         return 0;
01237     }
01238 
01239     if (op != target)
01240     {
01241         if (op->type == PLAYER)
01242         {
01243             new_draw_info_format(0, COLOR_WHITE, op, "You cast depletion on %s.", query_base_name(target, NULL));
01244         }
01245         else if (target->type == PLAYER)
01246         {
01247             new_draw_info_format(0, COLOR_WHITE, target, "%s casts remove depletion on you.", query_base_name(op, NULL));
01248         }
01249     }
01250 
01251     if ((depl = present_arch_in_ob(at, target)) != NULL)
01252     {
01253         for (i = 0; i < NUM_STATS; i++)
01254         {
01255             if (get_attr_value(&depl->stats, i))
01256             {
01257                 success++;
01258                 new_draw_info(0, COLOR_WHITE, target, restore_msg[i]);
01259             }
01260         }
01261 
01262         remove_ob(depl);
01263         fix_player(target);
01264     }
01265 
01266     if (op != target && op->type == PLAYER)
01267     {
01268         if (success)
01269         {
01270             new_draw_info(0, COLOR_WHITE, op, "Your prayer removes some depletion.");
01271         }
01272         else
01273         {
01274             new_draw_info(0, COLOR_WHITE, op, "There is no depletion.");
01275         }
01276     }
01277 
01278     /* If success, target got info before */
01279     if (op != target && target->type == PLAYER && !success)
01280     {
01281         new_draw_info(0, COLOR_WHITE, target, "There is no depletion.");
01282     }
01283 
01284     insert_spell_effect(spells[SP_REMOVE_DEPLETION].archname, target->map, target->x, target->y);
01285 
01286     return success;
01287 }
01288 
01297 int remove_curse(object *op, object *target, int type, int src)
01298 {
01299     object *tmp;
01300     int success = 0;
01301 
01302     if (!op || !target)
01303     {
01304         return 0;
01305     }
01306 
01307     if (op != target)
01308     {
01309         if (op->type == PLAYER)
01310         {
01311             new_draw_info_format(0, COLOR_WHITE, op, "You cast remove %s on %s.", type == SP_REMOVE_CURSE ? "curse" : "damnation", query_base_name(target, NULL));
01312         }
01313         else if (target->type == PLAYER)
01314         {
01315             new_draw_info_format(0, COLOR_WHITE, target, "%s casts remove %s on you.", query_base_name(op, NULL), type == SP_REMOVE_CURSE ? "curse" : "damnation");
01316         }
01317     }
01318 
01319     /* Player remove xx only removes applied stuff, npc remove clears ALL */
01320     for (tmp = target->inv; tmp; tmp = tmp->below)
01321     {
01322         if ((src == CAST_NPC || QUERY_FLAG(tmp, FLAG_APPLIED)) && (QUERY_FLAG(tmp, FLAG_CURSED) || (type == SP_REMOVE_DAMNATION && QUERY_FLAG(tmp, FLAG_DAMNED))))
01323         {
01324             if (tmp->level <= SK_level(op))
01325             {
01326                 success++;
01327 
01328                 if (type == SP_REMOVE_DAMNATION)
01329                 {
01330                     CLEAR_FLAG(tmp, FLAG_DAMNED);
01331                 }
01332 
01333                 CLEAR_FLAG(tmp, FLAG_CURSED);
01334 
01335                 if (target->type == PLAYER)
01336                 {
01337                     esrv_send_item(target, tmp);
01338                 }
01339             }
01340             /* Level of the items is too high for this remove curse */
01341             else
01342             {
01343                 if (target->type == PLAYER)
01344                 {
01345                     new_draw_info_format(0, COLOR_WHITE, target, "The %s's curse is stronger than the prayer!", query_base_name(tmp, NULL));
01346                 }
01347                 else if (op != target && op->type == PLAYER)
01348                 {
01349                     new_draw_info_format(0, COLOR_WHITE, op, "The %s's curse of %s is stronger than your prayer!", query_base_name(tmp, NULL), query_base_name(target, NULL));
01350                 }
01351             }
01352         }
01353     }
01354 
01355     if (op != target && op->type == PLAYER)
01356     {
01357         if (success)
01358         {
01359             new_draw_info(0, COLOR_WHITE, op, "Your prayer removes some curses.");
01360         }
01361         else
01362         {
01363             new_draw_info_format(0, COLOR_WHITE, op, "%s's items seem uncursed.", query_base_name(target, NULL));
01364         }
01365     }
01366 
01367     if (target->type == PLAYER)
01368     {
01369         if (success)
01370         {
01371             new_draw_info(0, COLOR_WHITE, target, "You feel like someone is helping you.");
01372         }
01373         else
01374         {
01375             if (src == CAST_NORMAL)
01376             {
01377                 new_draw_info(0, COLOR_WHITE, target, "You are not using any cursed items.");
01378             }
01379             else
01380             {
01381                 new_draw_info(0, COLOR_WHITE, target, "You hear maniacal laughter in the distance.");
01382             }
01383         }
01384     }
01385 
01386     insert_spell_effect(spells[SP_REMOVE_CURSE].archname, target->map, target->x, target->y);
01387 
01388     return success;
01389 }
01390 
01399 int do_cast_identify(object *tmp, object *op, int mode, int *done, int level)
01400 {
01401     if (QUERY_FLAG(tmp, FLAG_IDENTIFIED) || IS_SYS_INVISIBLE(tmp) || !need_identify(tmp))
01402     {
01403         return 1;
01404     }
01405 
01406     if (level < tmp->level)
01407     {
01408         if (op->type == PLAYER)
01409         {
01410             new_draw_info_format(0, COLOR_WHITE, op, "The %s is too powerful for this identify!", query_base_name(tmp, NULL));
01411         }
01412     }
01413     else
01414     {
01415         identify(tmp);
01416 
01417         if (op->type == PLAYER)
01418         {
01419             new_draw_info_format(0, COLOR_WHITE, op, "You have %s.", long_desc(tmp, NULL));
01420 
01421             if (tmp->msg)
01422             {
01423                 new_draw_info(0, COLOR_WHITE, op, "The item has a story:");
01424                 new_draw_info(0, COLOR_WHITE, op, tmp->msg);
01425             }
01426         }
01427 
01428         *done += 1;
01429     }
01430 
01431     if (mode == IDENTIFY_NORMAL && op->type == PLAYER && *done > CONTR(op)->skill_ptr[SK_LITERACY]->level + op->stats.Int)
01432     {
01433         return 0;
01434     }
01435 
01436     return 1;
01437 }
01438 
01448 int cast_identify(object *op, int level, object *single_ob, int mode)
01449 {
01450     int done = 0;
01451 
01452     insert_spell_effect(spells[SP_IDENTIFY].archname, op->map, op->x, op->y);
01453 
01454     if (mode == IDENTIFY_MARKED)
01455     {
01456         do_cast_identify(single_ob, op, mode, &done, level);
01457     }
01458     else
01459     {
01460         object *tmp = op->inv;
01461 
01462         if (single_ob && single_ob->type == CONTAINER)
01463         {
01464             tmp = single_ob->inv;
01465         }
01466 
01467         for ( ; tmp; tmp = tmp->below)
01468         {
01469             if (!do_cast_identify(tmp, op, mode, &done, level))
01470             {
01471                 break;
01472             }
01473         }
01474     }
01475 
01476     if (op->type == PLAYER && !done)
01477     {
01478         new_draw_info(0, COLOR_WHITE, op, "You can't reach anything unidentified in your inventory.");
01479     }
01480 
01481     return done;
01482 }
01483 
01489 int cast_consecrate(object *op)
01490 {
01491     object *tmp, *god = find_god(determine_god(op));
01492 
01493     if (!god)
01494     {
01495         new_draw_info(0, COLOR_WHITE, op, "You can't consecrate anything if you don't worship a god!");
01496         return 0;
01497     }
01498 
01499     for (tmp = op->below; tmp; tmp = tmp->below)
01500     {
01501         if (QUERY_FLAG(tmp, FLAG_IS_FLOOR))
01502         {
01503             break;
01504         }
01505 
01506         if (tmp->type == HOLY_ALTAR)
01507         {
01508             /* We use SK_level here instead of path_level mod because I think
01509              * all the gods should give equal chance of re-consecrating altars */
01510             if (tmp->level > SK_level(op))
01511             {
01512                 new_draw_info_format(0, COLOR_WHITE, op, "You are not powerful enough to reconsecrate the %s.", tmp->name);
01513                 return 0;
01514             }
01515             else if (tmp->other_arch == god->arch)
01516             {
01517                 new_draw_info_format(0, COLOR_WHITE, op, "That altar is already consecrated to %s.", god->name);
01518                 return 0;
01519             }
01520             else
01521             {
01522                 char buf[MAX_BUF], *cp;
01523                 object *new_altar;
01524 
01525                 snprintf(buf, sizeof(buf), "altar_%s", god->name);
01526 
01527                 for (cp = buf; *cp != '\0'; cp++)
01528                 {
01529                     *cp = tolower(*cp);
01530                 }
01531 
01532                 new_altar = get_archetype(buf);
01533                 new_altar->level = tmp->level;
01534                 new_altar->x = tmp->x;
01535                 new_altar->y = tmp->y;
01536                 new_altar->direction = tmp->direction;
01537 
01538                 if (QUERY_FLAG(new_altar, FLAG_IS_TURNABLE))
01539                 {
01540                     SET_ANIMATION(new_altar, (NUM_ANIMATIONS(new_altar) / NUM_FACINGS(new_altar)) * new_altar->direction);
01541                 }
01542 
01543                 if (QUERY_FLAG(tmp, FLAG_IS_BUILDABLE))
01544                 {
01545                     SET_FLAG(new_altar, FLAG_IS_BUILDABLE);
01546                 }
01547 
01548                 insert_ob_in_map(new_altar, tmp->map, NULL, 0);
01549                 remove_ob(tmp);
01550 
01551                 new_draw_info_format(0, COLOR_WHITE, op, "You consecrated the altar to %s!", god->name);
01552                 return 1;
01553             }
01554         }
01555     }
01556 
01557     new_draw_info(0, COLOR_WHITE, op, "You are not standing over an altar!");
01558     return 0;
01559 }
01560 
01569 int finger_of_death(object *op, object *target)
01570 {
01571     object *hitter;
01572     int dam;
01573 
01574     if (QUERY_FLAG(target, FLAG_UNDEAD))
01575     {
01576         new_draw_info_format(0, COLOR_WHITE, op, "The %s looks stronger!", query_name(target, NULL));
01577         target->stats.hp = target->stats.maxhp;
01578 
01579         if (!OBJECT_VALID(target->enemy, target->enemy_count))
01580         {
01581             set_npc_enemy(target, op, NULL);
01582         }
01583 
01584         return 1;
01585     }
01586 
01587     /* We create a hitter object -- the spell */
01588     hitter = arch_to_object(spellarch[SP_FINGER_DEATH]);
01589     hitter->level = SK_level(op);
01590     set_owner(hitter, op);
01591     hitter->x = target->x;
01592     hitter->y = target->y;
01593     insert_ob_in_map(hitter, target->map, op, 0);
01594 
01595     if (spell_attack_missed(hitter, target))
01596     {
01597         new_draw_info_format(0, COLOR_ORANGE, op, "Your finger of death misses %s!", target->name);
01598         remove_ob(hitter);
01599         return 1;
01600     }
01601 
01602     dam = SP_level_dam_adjust(op, SP_FINGER_DEATH, spells[SP_FINGER_DEATH].bdam, 0);
01603     hit_player(target, dam, hitter, AT_INTERNAL);
01604     remove_ob(hitter);
01605 
01606     return 1;
01607 }
01608 
01618 int cast_cause_disease(object *op, object *caster, int dir, archetype *disease_arch, int type)
01619 {
01620     int x = op->x, y = op->y, i, xt, yt;
01621     object *walk;
01622     mapstruct *m;
01623 
01624     /* Search in a line for a victim */
01625     for (i = 0; i < 5; i++)
01626     {
01627         x += freearr_x[dir];
01628         y += freearr_y[dir];
01629         xt = x;
01630         yt = y;
01631 
01632         if (!(m = get_map_from_coord(op->map, &xt, &yt)))
01633         {
01634             continue;
01635         }
01636 
01637         /* Check map flags for alive object */
01638         if (!(GET_MAP_FLAGS(m, xt, yt) & P_IS_ALIVE))
01639         {
01640             continue;
01641         }
01642 
01643         /* Search this square for a victim */
01644         for (walk = GET_MAP_OB(m, xt, yt); walk; walk = walk->above)
01645         {
01646             object *disease;
01647             int dam, strength;
01648 
01649             /* Found a victim */
01650             if (!QUERY_FLAG(walk, FLAG_MONSTER) && (walk->type != PLAYER || !pvp_area(op, walk)))
01651             {
01652                 continue;
01653             }
01654 
01655             disease = arch_to_object(disease_arch);
01656             dam = SP_level_dam_adjust(caster, type, spells[type].bdam, 0);
01657             strength = SP_level_strength_adjust(caster, type);
01658 
01659             set_owner(disease, op);
01660             disease->stats.exp = 0;
01661             disease->level = SK_level(caster);
01662 
01663             /* Try to get the experience into the correct category */
01664             if (op->chosen_skill && op->chosen_skill->exp_obj)
01665             {
01666                 disease->exp_obj = op->chosen_skill->exp_obj;
01667             }
01668 
01669             /* Do level adjustments */
01670             if (disease->stats.wc)
01671             {
01672                 disease->stats.wc += strength / 2;
01673             }
01674 
01675             if (disease->magic > 0)
01676             {
01677                 disease->magic += strength / 4;
01678             }
01679 
01680             if (disease->stats.maxhp > 0)
01681             {
01682                 disease->stats.maxhp += strength;
01683             }
01684 
01685             if (disease->stats.maxgrace > 0)
01686             {
01687                 disease->stats.maxgrace += strength;
01688             }
01689 
01690             if (disease->stats.dam)
01691             {
01692                 if (disease->stats.dam > 0)
01693                 {
01694                     disease->stats.dam += dam;
01695                 }
01696                 else
01697                 {
01698                     disease->stats.dam -= dam;
01699                 }
01700             }
01701 
01702             if (disease->last_sp)
01703             {
01704                 disease->last_sp -= 2 * dam;
01705 
01706                 if (disease->last_sp < 1)
01707                 {
01708                     disease->last_sp = 1;
01709                 }
01710             }
01711 
01712             if (disease->stats.maxsp)
01713             {
01714                 if (disease->stats.maxsp > 0)
01715                 {
01716                     disease->stats.maxsp += dam;
01717                 }
01718                 else
01719                 {
01720                     disease->stats.maxsp -= dam;
01721                 }
01722             }
01723 
01724             if (disease->stats.ac)
01725             {
01726                 disease->stats.ac += dam;
01727             }
01728 
01729             if (disease->last_eat)
01730             {
01731                 disease->last_eat -= dam;
01732             }
01733 
01734             if (disease->stats.hp)
01735             {
01736                 disease->stats.hp -= dam;
01737             }
01738 
01739             if (disease->stats.sp)
01740             {
01741                 disease->stats.sp -= dam;
01742             }
01743 
01744             if (infect_object(walk, disease, 1))
01745             {
01746                 new_draw_info_format(0, COLOR_WHITE, op, "You inflict %s on %s!", disease->name, walk->name);
01747                 return 1;
01748             }
01749         }
01750 
01751         /* No more infecting through walls. */
01752         if (wall(m, xt, yt))
01753         {
01754             return 0;
01755         }
01756     }
01757 
01758     new_draw_info(0, COLOR_WHITE, op, "No one caught anything!");
01759     return 0;
01760 }
01761 
01766 int cast_transform_wealth(object *op)
01767 {
01768     object *marked;
01769     sint64 val;
01770 
01771     if (op->type != PLAYER)
01772     {
01773         return 0;
01774     }
01775 
01776     /* Find the marked wealth. */
01777     marked = find_marked_object(op);
01778 
01779     if (!marked)
01780     {
01781         new_draw_info(0, COLOR_WHITE, op, "You need to mark an object to cast this spell.");
01782         return 0;
01783     }
01784 
01785     /* Check that it's really money. */
01786     if (marked->type != MONEY)
01787     {
01788         new_draw_info(0, COLOR_WHITE, op, "You can only cast this spell on wealth objects.");
01789         return 0;
01790     }
01791 
01792     /* Only allow coppers and silvers to be transformed. */
01793     if (strcmp(marked->arch->name, coins[NUM_COINS - 1]) && strcmp(marked->arch->name, coins[NUM_COINS - 2]))
01794     {
01795         new_draw_info_format(0, COLOR_WHITE, op, "You don't see a way to transform %s.", query_name(marked, op));
01796         return 0;
01797     }
01798 
01799     /* Figure out our value of money to give to player. */
01800     val = (marked->value * (marked->nrof ? marked->nrof : 1)) * TRANSFORM_WEALTH_SACRIFICE;
01801     /* We remove the money. */
01802     remove_ob(marked);
01803     esrv_del_item(CONTR(op), marked->count, marked->env);
01804     /* Now give the player the new money. */
01805     insert_coins(op, val);
01806     new_draw_info_format(0, COLOR_WHITE, op, "You transform %s into %s.", query_name(marked, op), cost_string_from_value(val));
01807     return 1;
01808 }