Crossfire Server, Branch 1.12
R12190
|
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 }