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
00040 #include <global.h>
00041 #include <object.h>
00042 #include <living.h>
00043 #ifndef __CEXTRACT__
00044 #include <sproto.h>
00045 #endif
00046 #include <spells.h>
00047 #include <sounds.h>
00048
00049
00050
00051
00052
00053
00054
00078 int fire_bolt(object *op, object *caster, int dir, object *spob, object *skill) {
00079 object *tmp = NULL;
00080 int mflags;
00081
00082 if (!spob->other_arch)
00083 return 0;
00084
00085 tmp = arch_to_object(spob->other_arch);
00086 if (tmp == NULL)
00087 return 0;
00088
00089
00090 tmp->stats.dam = spob->stats.dam+SP_level_dam_adjust(caster, spob);
00091 tmp->attacktype = spob->attacktype;
00092 if (spob->slaying)
00093 tmp->slaying = add_refcount(spob->slaying);
00094 tmp->range = spob->range+SP_level_range_adjust(caster, spob);
00095 tmp->duration = spob->duration+SP_level_duration_adjust(caster, spob);
00096 tmp->stats.Dex = spob->stats.Dex;
00097 tmp->stats.Con = spob->stats.Con;
00098
00099 tmp->direction = dir;
00100 if (QUERY_FLAG(tmp, FLAG_IS_TURNABLE))
00101 SET_ANIMATION(tmp, dir);
00102
00103 set_owner(tmp, op);
00104 set_spell_skill(op, caster, spob, tmp);
00105
00106 tmp->x = op->x+DIRX(tmp);
00107 tmp->y = op->y+DIRY(tmp);
00108 tmp->map = op->map;
00109
00110 mflags = get_map_flags(tmp->map, &tmp->map, tmp->x, tmp->y, &tmp->x, &tmp->y);
00111 if (mflags&P_OUT_OF_MAP) {
00112 free_object(tmp);
00113 return 0;
00114 }
00115 if (OB_TYPE_MOVE_BLOCK(tmp, GET_MAP_MOVE_BLOCK(tmp->map, tmp->x, tmp->y))) {
00116 if (!QUERY_FLAG(tmp, FLAG_REFLECTING)) {
00117 free_object(tmp);
00118 return 0;
00119 }
00120 tmp->x = op->x;
00121 tmp->y = op->y;
00122 tmp->direction = absdir(tmp->direction+4);
00123 tmp->map = op->map;
00124 }
00125 if ((tmp = insert_ob_in_map(tmp, tmp->map, op, 0)) != NULL)
00126 ob_process(tmp);
00127 return 1;
00128 }
00129
00130
00131
00132
00133
00134
00135
00136
00137
00144 void explode_bullet(object *op) {
00145 tag_t op_tag = op->count;
00146 object *tmp, *owner;
00147
00148 if (op->other_arch == NULL) {
00149 LOG(llevError, "BUG: explode_bullet(): op without other_arch\n");
00150 remove_ob(op);
00151 free_object(op);
00152 return;
00153 }
00154
00155 if (op->env) {
00156 object *env;
00157
00158 env = object_get_env_recursive(op);
00159 if (env->map == NULL || out_of_map(env->map, env->x, env->y)) {
00160 LOG(llevError, "BUG: explode_bullet(): env out of map\n");
00161 remove_ob(op);
00162 free_object(op);
00163 return;
00164 }
00165 remove_ob(op);
00166 op->x = env->x;
00167 op->y = env->y;
00168 insert_ob_in_map(op, env->map, op, INS_NO_MERGE|INS_NO_WALK_ON);
00169 } else if (out_of_map(op->map, op->x, op->y)) {
00170 LOG(llevError, "BUG: explode_bullet(): op out of map\n");
00171 remove_ob(op);
00172 free_object(op);
00173 return;
00174 }
00175
00176 if (op->attacktype) {
00177 hit_map(op, 0, op->attacktype, 1);
00178 if (was_destroyed(op, op_tag))
00179 return;
00180 }
00181
00182
00183 tmp = arch_to_object(op->other_arch);
00184
00185 copy_owner(tmp, op);
00186 if (tmp->skill)
00187 FREE_AND_CLEAR_STR(tmp->skill);
00188 if (op->skill)
00189 tmp->skill = add_refcount(op->skill);
00190
00191 owner = get_owner(op);
00192 if ((tmp->attacktype&AT_HOLYWORD || tmp->attacktype&AT_GODPOWER) && owner && !tailor_god_spell(tmp, owner)) {
00193 remove_ob(op);
00194 free_object(op);
00195 return;
00196 }
00197 tmp->x = op->x;
00198 tmp->y = op->y;
00199
00200
00201 if (op->type == SPELL_EFFECT && op->subtype == SP_BOMB) {
00202 tmp->attacktype = op->attacktype;
00203 tmp->range = op->range;
00204 tmp->stats.dam = op->stats.dam;
00205 tmp->duration = op->duration;
00206 } else {
00207 if (op->attacktype&AT_MAGIC)
00208 tmp->attacktype |= AT_MAGIC;
00209
00210 tmp->stats.dam = op->dam_modifier;
00211 tmp->range = op->stats.maxhp;
00212 tmp->duration = op->stats.hp;
00213 }
00214
00215
00216
00217
00218 tmp->stats.maxhp = op->count;
00219
00220
00221 if (tmp->type == SPELL_EFFECT && tmp->subtype == SP_CONE)
00222 tmp->stats.sp = op->direction;
00223
00224
00225 op->move_on = 0;
00226
00227 insert_ob_in_map(tmp, op->map, op, 0);
00228
00229 if (!was_destroyed(op, op_tag)) {
00230 remove_ob(op);
00231 free_object(op);
00232 }
00233 }
00234
00242 void check_bullet(object *op) {
00243 tag_t op_tag = op->count, tmp_tag;
00244 object *tmp;
00245 int dam, mflags;
00246 mapstruct *m;
00247 sint16 sx, sy;
00248
00249 mflags = get_map_flags(op->map, &m, op->x, op->y, &sx, &sy);
00250
00251 if (!(mflags&P_IS_ALIVE) && !OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, sx, sy)))
00252 return;
00253
00254 if (op->other_arch) {
00255
00256 explode_bullet(op);
00257 return;
00258 }
00259
00260
00261 if (!(mflags&P_IS_ALIVE))
00262 return;
00263
00264 for (tmp = GET_MAP_OB(op->map, op->x, op->y); tmp != NULL; tmp = tmp->above) {
00265 if (QUERY_FLAG(tmp, FLAG_ALIVE)) {
00266 tmp_tag = tmp->count;
00267 dam = hit_player(tmp, op->stats.dam, op, op->attacktype, 1);
00268 if (was_destroyed(op, op_tag) || !was_destroyed(tmp, tmp_tag) || (op->stats.dam -= dam) < 0) {
00269 if (!QUERY_FLAG(op, FLAG_REMOVED)) {
00270 remove_ob(op);
00271 free_object(op);
00272 return;
00273 }
00274 }
00275 }
00276 }
00277 }
00278
00279
00301 int fire_bullet(object *op, object *caster, int dir, object *spob) {
00302 object *tmp = NULL;
00303 int mflags;
00304
00305 if (!spob->other_arch)
00306 return 0;
00307
00308 tmp = arch_to_object(spob->other_arch);
00309 if (tmp == NULL)
00310 return 0;
00311
00312
00313 tmp->stats.dam = spob->stats.dam+SP_level_dam_adjust(caster, spob);
00314 tmp->attacktype = spob->attacktype;
00315 if (spob->slaying)
00316 tmp->slaying = add_refcount(spob->slaying);
00317
00318 tmp->range = 50;
00319
00320
00321 tmp->stats.hp = spob->duration+SP_level_duration_adjust(caster, spob);
00322 tmp->stats.maxhp = spob->range+SP_level_range_adjust(caster, spob);
00323 tmp->dam_modifier = spob->stats.food+SP_level_dam_adjust(caster, spob);
00324
00325 tmp->direction = dir;
00326 if (QUERY_FLAG(tmp, FLAG_IS_TURNABLE))
00327 SET_ANIMATION(tmp, dir);
00328
00329 set_owner(tmp, op);
00330 set_spell_skill(op, caster, spob, tmp);
00331
00332 tmp->x = op->x+freearr_x[dir];
00333 tmp->y = op->y+freearr_y[dir];
00334 tmp->map = op->map;
00335
00336 mflags = get_map_flags(tmp->map, &tmp->map, tmp->x, tmp->y, &tmp->x, &tmp->y);
00337 if (mflags&P_OUT_OF_MAP) {
00338 free_object(tmp);
00339 return 0;
00340 }
00341 if (OB_TYPE_MOVE_BLOCK(tmp, GET_MAP_MOVE_BLOCK(tmp->map, tmp->x, tmp->y))) {
00342 if (!QUERY_FLAG(tmp, FLAG_REFLECTING)) {
00343 free_object(tmp);
00344 return 0;
00345 }
00346 tmp->x = op->x;
00347 tmp->y = op->y;
00348 tmp->direction = absdir(tmp->direction+4);
00349 tmp->map = op->map;
00350 }
00351 if ((tmp = insert_ob_in_map(tmp, tmp->map, op, 0)) != NULL) {
00352 check_bullet(tmp);
00353 }
00354 return 1;
00355 }
00356
00357
00358
00359
00360
00361
00362
00369 void cone_drop(object *op) {
00370 object *new_ob = arch_to_object(op->other_arch);
00371
00372 new_ob->x = op->x;
00373 new_ob->y = op->y;
00374 new_ob->level = op->level;
00375 set_owner(new_ob, op->owner);
00376
00377
00378 if (op->skill && op->skill != new_ob->skill) {
00379 if (new_ob->skill)
00380 free_string(new_ob->skill);
00381 new_ob->skill = add_refcount(op->skill);
00382 }
00383 insert_ob_in_map(new_ob, op->map, op, 0);
00384 }
00385
00403 int cast_cone(object *op, object *caster, int dir, object *spell) {
00404 object *tmp;
00405 int i, success = 0, range_min = -1, range_max = 1;
00406 mapstruct *m;
00407 sint16 sx, sy;
00408 MoveType movetype;
00409
00410 if (!spell->other_arch)
00411 return 0;
00412
00413 if (op->type == PLAYER && QUERY_FLAG(op, FLAG_UNDEAD) && op->attacktype&AT_TURN_UNDEAD) {
00414 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR, "Your undead nature prevents you from turning undead!", NULL);
00415 return 0;
00416 }
00417
00418 if (!dir) {
00419 range_min = 0;
00420 range_max = 8;
00421 }
00422
00423
00424
00425
00426
00427 movetype = spell->other_arch->clone.move_type;
00428
00429 for (i = range_min; i <= range_max; i++) {
00430 sint16 x, y, d;
00431
00432
00433
00434
00435
00436
00437 d = dir+i;
00438 while (d < 0)
00439 d += 8;
00440 while (d > 8)
00441 d -= 8;
00442
00443
00444
00445
00446
00447
00448
00449
00450 if (caster->type != RUNE && d == 0) {
00451 if (dir != 0)
00452 d = 8;
00453 else
00454 continue;
00455 }
00456
00457 x = op->x+freearr_x[d];
00458 y = op->y+freearr_y[d];
00459
00460 if (get_map_flags(op->map, &m, x, y, &sx, &sy)&P_OUT_OF_MAP)
00461 continue;
00462
00463 if ((movetype&GET_MAP_MOVE_BLOCK(m, sx, sy)) == movetype)
00464 continue;
00465
00466 success = 1;
00467 tmp = arch_to_object(spell->other_arch);
00468 set_owner(tmp, op);
00469 set_spell_skill(op, caster, spell, tmp);
00470 tmp->level = caster_level(caster, spell);
00471 tmp->x = sx;
00472 tmp->y = sy;
00473 tmp->attacktype = spell->attacktype;
00474
00475
00476 if ((tmp->attacktype&AT_HOLYWORD) || (tmp->attacktype&AT_GODPOWER)) {
00477 if (!tailor_god_spell(tmp, op))
00478 return 0;
00479 }
00480
00481 if (dir)
00482 tmp->stats.sp = dir;
00483 else
00484 tmp->stats.sp = i;
00485
00486 tmp->range = spell->range+SP_level_range_adjust(caster, spell);
00487
00488
00489 if (dir == 0) {
00490 tmp->range /= 4;
00491 if (tmp->range < 2 && spell->range >= 2)
00492 tmp->range = 2;
00493 }
00494 tmp->stats.dam = spell->stats.dam+SP_level_dam_adjust(caster, spell);
00495 tmp->duration = spell->duration+SP_level_duration_adjust(caster, spell);
00496
00497
00498 if (tmp->attacktype&AT_FEAR) {
00499 if (caster->type == PLAYER)
00500 tmp->duration += fear_bonus[caster->stats.Cha];
00501 else
00502 tmp->duration += caster->level/3;
00503 }
00504 if (tmp->attacktype&(AT_HOLYWORD|AT_TURN_UNDEAD)) {
00505 if (caster->type == PLAYER)
00506 tmp->duration += turn_bonus[caster->stats.Wis]/5;
00507 else
00508 tmp->duration += caster->level/3;
00509 }
00510
00511 if (!(tmp->move_type&MOVE_FLY_LOW))
00512 LOG(llevDebug, "cast_cone(): arch %s doesn't have flying 1\n", spell->other_arch->name);
00513
00514 if (!tmp->move_on && tmp->stats.dam) {
00515 LOG(llevDebug, "cast_cone(): arch %s doesn't have move_on set\n", spell->other_arch->name);
00516 }
00517 insert_ob_in_map(tmp, m, op, 0);
00518
00519
00520
00521
00522 tmp->stats.maxhp = tmp->count;
00523
00524 if (tmp->other_arch)
00525 cone_drop(tmp);
00526 }
00527 return success;
00528 }
00529
00530
00531
00532
00533
00534
00535
00552 int create_bomb(object *op, object *caster, int dir, object *spell) {
00553 object *tmp;
00554 int mflags;
00555 sint16 dx = op->x+freearr_x[dir], dy = op->y+freearr_y[dir];
00556 mapstruct *m;
00557
00558 mflags = get_map_flags(op->map, &m, dx, dy, &dx, &dy);
00559 if ((mflags&P_OUT_OF_MAP) || (GET_MAP_MOVE_BLOCK(m, dx, dy)&MOVE_WALK)) {
00560 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR, "There is something in the way.", NULL);
00561 return 0;
00562 }
00563 tmp = arch_to_object(spell->other_arch);
00564
00565
00566 tmp->range = spell->range+SP_level_range_adjust(caster, spell);
00567 tmp->stats.dam = spell->stats.dam+SP_level_dam_adjust(caster, spell);
00568 tmp->duration = spell->duration+SP_level_duration_adjust(caster, spell);
00569 tmp->attacktype = spell->attacktype;
00570
00571 set_owner(tmp, op);
00572 set_spell_skill(op, caster, spell, tmp);
00573 tmp->x = dx;
00574 tmp->y = dy;
00575 insert_ob_in_map(tmp, m, op, 0);
00576 return 1;
00577 }
00578
00579
00580
00581
00582
00583
00584
00603 static object *get_pointed_target(object *op, int dir, int range, int type) {
00604 object *target;
00605 sint16 x, y;
00606 int dist, mflags;
00607 mapstruct *mp;
00608
00609 if (dir == 0)
00610 return NULL;
00611
00612 for (dist = 1; dist < range; dist++) {
00613 x = op->x+freearr_x[dir]*dist;
00614 y = op->y+freearr_y[dir]*dist;
00615 mp = op->map;
00616 mflags = get_map_flags(op->map, &mp, x, y, &x, &y);
00617
00618 if (mflags&P_OUT_OF_MAP)
00619 return NULL;
00620 if ((type&SPELL_MANA) && (mflags&P_NO_MAGIC))
00621 return NULL;
00622 if ((type&SPELL_GRACE) && (mflags&P_NO_CLERIC))
00623 return NULL;
00624 if (GET_MAP_MOVE_BLOCK(mp, x, y)&MOVE_FLY_LOW)
00625 return NULL;
00626
00627 if (mflags&P_IS_ALIVE) {
00628 for (target = GET_MAP_OB(mp, x, y); target; target = target->above) {
00629 if (QUERY_FLAG(target->head ? target->head : target, FLAG_MONSTER)) {
00630 return target;
00631 }
00632 }
00633 }
00634 }
00635 return NULL;
00636 }
00637
00638
00655 int cast_smite_spell(object *op, object *caster, int dir, object *spell) {
00656 object *effect, *target;
00657 const object *god = find_god(determine_god(op));
00658 int range;
00659
00660
00661 range = spell->range+SP_level_range_adjust(caster, spell);
00662 target = get_pointed_target(op, dir, 50, spell->stats.grace ? SPELL_GRACE : SPELL_MANA);
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673 if (!target
00674 || QUERY_FLAG(target, FLAG_REFL_SPELL)
00675 || (!god && spell->stats.grace)
00676 || (target->title && god && !strcmp(target->title, god->name))
00677 || (target->race && god && strstr(target->race, god->race))) {
00678 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE, "Your request is unheeded.", NULL);
00679 return 0;
00680 }
00681
00682 if (spell->other_arch)
00683 effect = arch_to_object(spell->other_arch);
00684 else
00685 return 0;
00686
00687
00688 effect->level = caster_level(caster, spell);
00689 effect->attacktype = spell->attacktype;
00690 if (effect->attacktype&(AT_HOLYWORD|AT_GODPOWER)) {
00691 if (tailor_god_spell(effect, op))
00692 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_SUCCESS,
00693 "%s answers your call!",
00694 "%s answers your call!",
00695 determine_god(op));
00696 else {
00697 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE, "Your request is ignored.", NULL);
00698 return 0;
00699 }
00700 }
00701
00702
00703 effect->range = spell->range+SP_level_range_adjust(caster, spell);
00704 effect->duration = spell->duration+SP_level_range_adjust(caster, spell);
00705
00706 if (effect->attacktype&AT_DEATH) {
00707 effect->level = spell->stats.dam+SP_level_dam_adjust(caster, spell);
00708
00709
00710 if QUERY_FLAG(target, FLAG_UNDEAD) {
00711 if (random_roll(0, 2, op, PREFER_LOW)) {
00712 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE, "Idiot! Your spell boomerangs!", NULL);
00713 effect->x = op->x;
00714 effect->y = op->y;
00715 } else {
00716 char target_name[HUGE_BUF];
00717
00718 query_name(target, target_name, HUGE_BUF);
00719 draw_ext_info_format(NDI_UNIQUE, 0, op,
00720 MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
00721 "The %s looks stronger!",
00722 "The %s looks stronger!",
00723 target_name);
00724 target->stats.hp = target->stats.maxhp*2;
00725 free_object(effect);
00726 return 0;
00727 }
00728 }
00729 } else {
00730
00731 effect->stats.dam = spell->stats.dam+SP_level_dam_adjust(caster, spell);
00732 }
00733
00734 if (effect->type == SPELL_EFFECT && effect->subtype == SP_EXPLOSION) {
00735
00736
00737
00738
00739
00740
00741 effect->stats.maxhp = spell->count;
00742 }
00743
00744 set_owner(effect, op);
00745 set_spell_skill(op, caster, spell, effect);
00746
00747
00748 effect->x = target->x;
00749 effect->y = target->y;
00750 insert_ob_in_map(effect, target->map, op, 0);
00751
00752 return 1;
00753 }
00754
00755
00756
00757
00758
00777 static int make_object_glow(object *op, int radius, int time) {
00778 object *tmp;
00779
00780
00781 if (op->path_denied&PATH_LIGHT)
00782 return 0;
00783
00784 tmp = create_archetype(FORCE_NAME);
00785 tmp->speed = 0.01;
00786 tmp->stats.food = time;
00787 SET_FLAG(tmp, FLAG_IS_USED_UP);
00788 tmp->glow_radius = radius;
00789 if (tmp->glow_radius > MAX_LIGHT_RADII)
00790 tmp->glow_radius = MAX_LIGHT_RADII;
00791
00792 tmp->x = op->x;
00793 tmp->y = op->y;
00794 if (tmp->speed < MIN_ACTIVE_SPEED)
00795 tmp->speed = MIN_ACTIVE_SPEED;
00796 tmp = insert_ob_in_ob(tmp, op);
00797 if (tmp->glow_radius > op->glow_radius)
00798 op->glow_radius = tmp->glow_radius;
00799
00800 if (!tmp->env || op != tmp->env) {
00801 LOG(llevError, "make_object_glow() failed to insert glowing force in %s\n", op->name);
00802 return 0;
00803 }
00804 return 1;
00805 }
00806
00819 int cast_destruction(object *op, object *caster, object *spell_ob) {
00820 int i, j, range, mflags, friendly = 0, dam, dur;
00821 sint16 sx, sy;
00822 mapstruct *m;
00823 object *tmp;
00824 const char *skill;
00825
00826 range = spell_ob->range+SP_level_range_adjust(caster, spell_ob);
00827 dam = spell_ob->stats.dam+SP_level_dam_adjust(caster, spell_ob);
00828 dur = spell_ob->duration+SP_level_duration_adjust(caster, spell_ob);
00829 if (QUERY_FLAG(op, FLAG_FRIENDLY) || op->type == PLAYER)
00830 friendly = 1;
00831
00832
00833
00834
00835
00836
00837
00838 skill = op->skill;
00839 if (caster == op)
00840 op->skill = spell_ob->skill;
00841 else if (caster->skill)
00842 op->skill = caster->skill;
00843 else
00844 op->skill = NULL;
00845
00846 change_skill(op, find_skill_by_name(op, op->skill), 1);
00847
00848 for (i = -range; i < range; i++) {
00849 for (j = -range; j < range; j++) {
00850 m = op->map;
00851 sx = op->x+i;
00852 sy = op->y+j;
00853 mflags = get_map_flags(m, &m, sx, sy, &sx, &sy);
00854 if (mflags&P_OUT_OF_MAP)
00855 continue;
00856 if (mflags&P_IS_ALIVE) {
00857 for (tmp = GET_MAP_OB(m, sx, sy); tmp; tmp = tmp->above) {
00858 if (QUERY_FLAG(tmp, FLAG_ALIVE) || tmp->type == PLAYER)
00859 break;
00860 }
00861 if (tmp) {
00862 if (tmp->head)
00863 tmp = tmp->head;
00864
00865 if ((friendly && !QUERY_FLAG(tmp, FLAG_FRIENDLY) && tmp->type != PLAYER)
00866 || (!friendly && (QUERY_FLAG(tmp, FLAG_FRIENDLY) || tmp->type == PLAYER))) {
00867 if (spell_ob->subtype == SP_DESTRUCTION) {
00868 hit_player(tmp, dam, op, spell_ob->attacktype, 0);
00869 if (spell_ob->other_arch) {
00870 tmp = arch_to_object(spell_ob->other_arch);
00871 tmp->x = sx;
00872 tmp->y = sy;
00873 insert_ob_in_map(tmp, m, op, 0);
00874 }
00875 } else if (spell_ob->subtype == SP_FAERY_FIRE && tmp->resist[ATNR_MAGIC] != 100) {
00876 if (make_object_glow(tmp, 1, dur) && spell_ob->other_arch) {
00877 object *effect = arch_to_object(spell_ob->other_arch);
00878 effect->x = sx;
00879 effect->y = sy;
00880 insert_ob_in_map(effect, m, op, 0);
00881 }
00882 }
00883 }
00884 }
00885 }
00886 }
00887 }
00888 op->skill = skill;
00889 return 1;
00890 }
00891
00892
00893
00894
00895
00896
00897
00914 int cast_curse(object *op, object *caster, object *spell_ob, int dir) {
00915 const object *god = find_god(determine_god(op));
00916 object *tmp, *force;
00917
00918 tmp = get_pointed_target(op, (dir == 0) ? op->direction : dir, spell_ob->range, SPELL_GRACE);
00919 if (!tmp) {
00920 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE, "There is no one in that direction to curse.", NULL);
00921 return 0;
00922 }
00923
00924
00925 for (force = tmp->inv; force != NULL; force = force->below) {
00926 if (force->type == FORCE && force->subtype == FORCE_CHANGE_ABILITY) {
00927 if (force->name == spell_ob->name) {
00928 break;
00929 } else if (spell_ob->race && spell_ob->race == force->name) {
00930 draw_ext_info_format(NDI_UNIQUE, 0, op,
00931 MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE,
00932 "You can not cast %s while %s is in effect",
00933 "You can not cast %s while %s is in effect",
00934 spell_ob->name, force->name_pl);
00935 return 0;
00936 }
00937 }
00938 }
00939
00940 if (force == NULL) {
00941 force = create_archetype(FORCE_NAME);
00942 force->subtype = FORCE_CHANGE_ABILITY;
00943 free_string(force->name);
00944 if (spell_ob->race)
00945 force->name = add_refcount(spell_ob->race);
00946 else
00947 force->name = add_refcount(spell_ob->name);
00948 free_string(force->name_pl);
00949 force->name_pl = add_refcount(spell_ob->name);
00950 } else {
00951 int duration;
00952
00953 duration = spell_ob->duration+SP_level_duration_adjust(caster, spell_ob)*50;
00954 if (duration > force->duration) {
00955 force->duration = duration;
00956 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_SUCCESS, "You recast the spell while in effect.", NULL);
00957 } else {
00958 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE, "Recasting the spell had no effect.", NULL);
00959 }
00960 return 1;
00961 }
00962 force->duration = spell_ob->duration+SP_level_duration_adjust(caster, spell_ob)*50;
00963 force->speed = 1.0;
00964 force->speed_left = -1.0;
00965 SET_FLAG(force, FLAG_APPLIED);
00966
00967 if (god) {
00968 if (spell_ob->last_grace)
00969 force->path_repelled = god->path_repelled;
00970 if (spell_ob->last_grace)
00971 force->path_denied = god->path_denied;
00972 draw_ext_info_format(NDI_UNIQUE, 0, tmp, MSG_TYPE_VICTIM, MSG_TYPE_VICTIM_SPELL,
00973 "You are a victim of %s's curse!",
00974 "You are a victim of %s's curse!",
00975 god->name);
00976 } else
00977 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE, "Your curse seems empty.", NULL);
00978
00979
00980 if (tmp != op && op->type == PLAYER)
00981 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_SUCCESS,
00982 "You curse %s!",
00983 "You curse %s!",
00984 tmp->name);
00985
00986 force->stats.ac = spell_ob->stats.ac;
00987 force->stats.wc = spell_ob->stats.wc;
00988
00989 change_abil(tmp, force);
00990 insert_ob_in_ob(force, tmp);
00991 fix_object(tmp);
00992 return 1;
00993 }
00994
00995
00996
00997
00998
00999
01000
01014 int mood_change(object *op, object *caster, object *spell) {
01015 object *tmp, *head;
01016 const object *god;
01017 int done_one, range, mflags, level, at, best_at;
01018 sint16 x, y, nx, ny;
01019 mapstruct *m;
01020 const char *race;
01021
01022
01023
01024
01025 god = find_god(determine_god(op));
01026 level = caster_level(caster, spell);
01027 range = spell->range+SP_level_range_adjust(caster, spell);
01028
01029
01030
01031
01032
01033 if (!spell->race)
01034 race = NULL;
01035 else if (god && !strcmp(spell->race, "GOD_SLAYING"))
01036 race = god->slaying;
01037 else if (god && !strcmp(spell->race, "GOD_FRIEND"))
01038 race = god->race;
01039 else
01040 race = spell->race;
01041
01042 for (x = op->x-range; x <= op->x+range; x++)
01043 for (y = op->y-range; y <= op->y+range; y++) {
01044 done_one = 0;
01045 m = op->map;
01046 nx = x;
01047 ny = y;
01048 mflags = get_map_flags(m, &m, x, y, &nx, &ny);
01049 if (mflags&P_OUT_OF_MAP)
01050 continue;
01051
01052
01053 if (!(mflags&P_IS_ALIVE))
01054 continue;
01055
01056 for (tmp = GET_MAP_OB(m, nx, ny); tmp; tmp = tmp->above)
01057 if (QUERY_FLAG(tmp, FLAG_MONSTER))
01058 break;
01059
01060
01061 if (!tmp || tmp->type == PLAYER)
01062 continue;
01063
01064
01065 if (tmp->head)
01066 head = tmp->head;
01067 else
01068 head = tmp;
01069
01070
01071 if (race && head->race && !strstr(race, head->race))
01072 continue;
01073 if (QUERY_FLAG(head, FLAG_UNDEAD) && !QUERY_FLAG(spell, FLAG_UNDEAD))
01074 continue;
01075
01076
01077 best_at = -1;
01078 if (spell->attacktype) {
01079 for (at = 0; at < NROFATTACKS; at++)
01080 if (spell->attacktype&(1<<at))
01081 if (best_at == -1 || head->resist[at] > head->resist[best_at])
01082 best_at = at;
01083
01084 if (best_at == -1)
01085 at = 0;
01086 else {
01087 if (head->resist[best_at] == 100)
01088 continue;
01089 else
01090 at = head->resist[best_at]/5;
01091 }
01092 at -= level/5;
01093 if (did_make_save(head, head->level, at))
01094 continue;
01095 } else {
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108 if (head->level > level)
01109 continue;
01110 if (random_roll(0, 100, caster, PREFER_LOW) >= (20+MIN(50, 2*(level-head->level))))
01111
01112 continue;
01113 }
01114
01115
01116
01117
01118 if (QUERY_FLAG(spell, FLAG_MONSTER)) {
01119 CLEAR_FLAG(head, FLAG_SLEEP);
01120 if (QUERY_FLAG(head, FLAG_FRIENDLY))
01121 remove_friendly_object(head);
01122
01123 done_one = 1;
01124 head->enemy = op;
01125 }
01126
01127
01128 if (QUERY_FLAG(spell, FLAG_UNAGGRESSIVE) && !QUERY_FLAG(head, FLAG_UNAGGRESSIVE)) {
01129 SET_FLAG(head, FLAG_UNAGGRESSIVE);
01130 head->enemy = NULL;
01131 done_one = 1;
01132 }
01133
01134
01135 if (QUERY_FLAG(spell, FLAG_BERSERK) && !QUERY_FLAG(head, FLAG_BERSERK)) {
01136 SET_FLAG(head, FLAG_BERSERK);
01137 done_one = 1;
01138 }
01139
01140 if (QUERY_FLAG(spell, FLAG_NO_ATTACK) && !QUERY_FLAG(head, FLAG_FRIENDLY)) {
01141 SET_FLAG(head, FLAG_FRIENDLY);
01142
01143
01144
01145 CLEAR_FLAG(head, FLAG_GENERATOR);
01146 set_owner(head, op);
01147 set_spell_skill(op, caster, spell, head);
01148 add_friendly_object(head);
01149 head->attack_movement = PETMOVE;
01150 done_one = 1;
01151 share_exp(op, head->stats.exp/2, head->skill, SK_EXP_ADD_SKILL);
01152 head->stats.exp = 0;
01153 }
01154
01155
01156 if (done_one && spell->other_arch) {
01157 tmp = arch_to_object(spell->other_arch);
01158 tmp->x = nx;
01159 tmp->y = ny;
01160 insert_ob_in_map(tmp, m, op, 0);
01161 }
01162 }
01163
01164 return 1;
01165 }
01166
01167
01185 int fire_swarm(object *op, object *caster, object *spell, int dir) {
01186 object *tmp;
01187 int i;
01188
01189 if (!spell->other_arch)
01190 return 0;
01191
01192 tmp = create_archetype(SWARM_SPELL);
01193 tmp->x = op->x;
01194 tmp->y = op->y;
01195 set_owner(tmp, op);
01196 set_spell_skill(op, caster, spell, tmp);
01197
01198 tmp->level = caster_level(caster, spell);
01199 tmp->spell = arch_to_object(spell->other_arch);
01200
01201 tmp->attacktype = tmp->spell->attacktype;
01202
01203 if (tmp->attacktype&AT_HOLYWORD || tmp->attacktype&AT_GODPOWER) {
01204 if (!tailor_god_spell(tmp, op))
01205 return 1;
01206 }
01207 tmp->duration = SP_level_duration_adjust(caster, spell);
01208 for (i = 0; i < spell->duration; i++)
01209 tmp->duration += die_roll(1, 3, op, PREFER_HIGH);
01210
01211 tmp->direction = dir;
01212 tmp->invisible = 1;
01213 insert_ob_in_map(tmp, op->map, op, 0);
01214 return 1;
01215 }
01216
01235 int cast_light(object *op, object *caster, object *spell, int dir) {
01236 object *target = NULL, *tmp = NULL;
01237 sint16 x, y;
01238 int dam, mflags;
01239 mapstruct *m;
01240
01241 dam = spell->stats.dam+SP_level_dam_adjust(caster, spell);
01242
01243 if (!dir) {
01244 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR, "In what direction?", NULL);
01245 return 0;
01246 }
01247
01248 x = op->x+freearr_x[dir];
01249 y = op->y+freearr_y[dir];
01250 m = op->map;
01251
01252 mflags = get_map_flags(m, &m, x, y, &x, &y);
01253
01254 if (mflags&P_OUT_OF_MAP) {
01255 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE, "Nothing is there.", NULL);
01256 return 0;
01257 }
01258
01259 if (mflags&P_IS_ALIVE && spell->attacktype) {
01260 for (target = GET_MAP_OB(m, x, y); target; target = target->above)
01261 if (QUERY_FLAG(target, FLAG_MONSTER)) {
01262
01263 if (target->head)
01264 target = target->head;
01265 (void)hit_player(target, dam, op, spell->attacktype, 1);
01266 return 1;
01267 }
01268 }
01269
01270
01271 if (OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, x, y))) {
01272 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR, "Something is in the way.", NULL);
01273 return 0;
01274 }
01275
01276
01277 tmp = arch_to_object(spell->other_arch);
01278 if (!tmp) {
01279 LOG(llevError, "Error: spell arch for cast_light() missing.\n");
01280 return 0;
01281 }
01282 tmp->stats.food = spell->duration+SP_level_duration_adjust(caster, spell);
01283 if (tmp->glow_radius) {
01284 tmp->glow_radius = spell->range+SP_level_range_adjust(caster, spell);
01285 if (tmp->glow_radius > MAX_LIGHT_RADII)
01286 tmp->glow_radius = MAX_LIGHT_RADII;
01287 }
01288 tmp->x = x;
01289 tmp->y = y;
01290 insert_ob_in_map(tmp, m, op, 0);
01291 return 1;
01292 }
01293
01310 int cast_cause_disease(object *op, object *caster, object *spell, int dir) {
01311 sint16 x, y;
01312 int i, mflags, range, dam_mod, dur_mod;
01313 object *walk, *target_head;
01314 mapstruct *m;
01315
01316 x = op->x;
01317 y = op->y;
01318
01319
01320
01321
01322 if (!dir)
01323 dir = op->facing;
01324 if (!dir)
01325 return 0;
01326
01327
01328 range = spell->range+SP_level_range_adjust(caster, spell);
01329 dam_mod = SP_level_dam_adjust(caster, spell);
01330 dur_mod = SP_level_duration_adjust(caster, spell);
01331
01332
01333 for (i = 1; i < range; i++) {
01334 x = op->x+i*freearr_x[dir];
01335 y = op->y+i*freearr_y[dir];
01336 m = op->map;
01337
01338 mflags = get_map_flags(m, &m, x, y, &x, &y);
01339
01340 if (mflags&P_OUT_OF_MAP)
01341 return 0;
01342
01343
01344 if (GET_MAP_MOVE_BLOCK(m, x, y)&MOVE_FLY_LOW)
01345 return 0;
01346
01347
01348 if (mflags&P_IS_ALIVE) {
01349
01350 for (walk = GET_MAP_OB(m, x, y); walk; walk = walk->above) {
01351
01352 target_head = walk;
01353 while (target_head->head)
01354 target_head = target_head->head;
01355 if (QUERY_FLAG(target_head, FLAG_MONSTER) || (target_head->type == PLAYER)) {
01356 object *disease = arch_to_object(spell->other_arch);
01357
01358 set_owner(disease, op);
01359 set_spell_skill(op, caster, spell, disease);
01360 disease->stats.exp = 0;
01361 disease->level = caster_level(caster, spell);
01362
01363
01364 if (disease->stats.wc)
01365 disease->stats.wc += dur_mod/2;
01366
01367 if (disease->magic > 0)
01368 disease->magic += dur_mod/4;
01369
01370 if (disease->stats.maxhp > 0)
01371 disease->stats.maxhp += dur_mod;
01372
01373 if (disease->stats.maxgrace > 0)
01374 disease->stats.maxgrace += dur_mod;
01375
01376 if (disease->stats.dam) {
01377 if (disease->stats.dam > 0)
01378 disease->stats.dam += dam_mod;
01379 else
01380 disease->stats.dam -= dam_mod;
01381 }
01382
01383 if (disease->last_sp) {
01384 disease->last_sp -= 2*dam_mod;
01385 if (disease->last_sp < 1)
01386 disease->last_sp = 1;
01387 }
01388
01389 if (disease->stats.maxsp) {
01390 if (disease->stats.maxsp > 0)
01391 disease->stats.maxsp += dam_mod;
01392 else
01393 disease->stats.maxsp -= dam_mod;
01394 }
01395
01396 if (disease->stats.ac)
01397 disease->stats.ac += dam_mod;
01398
01399 if (disease->last_eat)
01400 disease->last_eat -= dam_mod;
01401
01402 if (disease->stats.hp)
01403 disease->stats.hp -= dam_mod;
01404
01405 if (disease->stats.sp)
01406 disease->stats.sp -= dam_mod;
01407
01408 if (infect_object(target_head, disease, 1)) {
01409 object *flash;
01410
01411 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_SUCCESS, "You inflict %s on %s!", NULL, disease->name, target_head->name);
01412
01413 free_object(disease);
01414 flash = create_archetype(ARCH_DETECT_MAGIC);
01415 flash->x = x;
01416 flash->y = y;
01417 flash->map = walk->map;
01418 insert_ob_in_map(flash, walk->map, op, 0);
01419 return 1;
01420 }
01421 free_object(disease);
01422 }
01423 }
01424 }
01425 }
01426 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE, "No one caught anything!", NULL);
01427 return 1;
01428 }