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