ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/spell_attack.C
(Generate patch)

Comparing deliantra/server/server/spell_attack.C (file contents):
Revision 1.55 by root, Sat May 17 00:17:02 2008 UTC vs.
Revision 1.65 by root, Mon Sep 29 10:20:49 2008 UTC

36/* this function checks to see if a spell pushes objects as well 36/* this function checks to see if a spell pushes objects as well
37 * as flies over and damages them (only used for cones for now) 37 * as flies over and damages them (only used for cones for now)
38 * but moved here so it could be applied to bolts too 38 * but moved here so it could be applied to bolts too
39 * op is the spell object. 39 * op is the spell object.
40 */ 40 */
41
42void 41void
43check_spell_knockback (object *op) 42check_spell_knockback (object *op)
44{ 43{
45 object *tmp, *tmp2; /* object on the map */
46 int weight_move; 44 int weight_move;
47 int frictionmod = 2; /*poor man's physics - multipy targets weight by this amount */ 45 int frictionmod = 2; /*poor man's physics - multipy targets weight by this amount */
48 46
49 if (!op->weight) 47 if (!op->weight)
50 { /*shouldn't happen but if cone object has no weight drop out */ 48 { /*shouldn't happen but if cone object has no weight drop out */
55 { 53 {
56 weight_move = op->weight + (op->weight * op->level) / 3; 54 weight_move = op->weight + (op->weight * op->level) / 3;
57 /*LOG (llevDebug, "DEBUG: arch weighs %d and masses %d (%s,level %d)\n", op->weight,weight_move,op->name,op->level); */ 55 /*LOG (llevDebug, "DEBUG: arch weighs %d and masses %d (%s,level %d)\n", op->weight,weight_move,op->name,op->level); */
58 } 56 }
59 57
60 for (tmp = GET_MAP_OB (op->map, op->x, op->y); tmp != NULL; tmp = tmp->above) 58 for (object *tmp = op->ms ().bot; tmp; tmp = tmp->above)
61 { 59 {
62 int num_sections = 1; 60 int num_sections = 1;
63 61
64 /* don't move DM */ 62 /* don't move DM */
65 if (QUERY_FLAG (tmp, FLAG_WIZ)) 63 if (QUERY_FLAG (tmp, FLAG_WIZ))
72 /* don't move floors or immobile objects */ 70 /* don't move floors or immobile objects */
73 if (QUERY_FLAG (tmp, FLAG_IS_FLOOR) || (!QUERY_FLAG (tmp, FLAG_ALIVE) && QUERY_FLAG (tmp, FLAG_NO_PICK))) 71 if (QUERY_FLAG (tmp, FLAG_IS_FLOOR) || (!QUERY_FLAG (tmp, FLAG_ALIVE) && QUERY_FLAG (tmp, FLAG_NO_PICK)))
74 continue; 72 continue;
75 73
76 /* count the object's sections */ 74 /* count the object's sections */
77 for (tmp2 = tmp; tmp2 != NULL; tmp2 = tmp2->more) 75 for (object *tmp2 = tmp; tmp2; tmp2 = tmp2->more)
78 num_sections++; 76 num_sections++;
79 77
80 /* I'm not sure if it makes sense to divide by num_sections - bigger 78 /* I'm not sure if it makes sense to divide by num_sections - bigger
81 * objects should be harder to move, and we are moving the entire 79 * objects should be harder to move, and we are moving the entire
82 * object, not just the head, so the total weight should be relevant. 80 * object, not just the head, so the total weight should be relevant.
106 * 104 *
107 * BOLT CODE 105 * BOLT CODE
108 * 106 *
109 ***************************************************************************/ 107 ***************************************************************************/
110 108
111/* Causes op to fork. op is the original bolt, tmp 109/* Causes op to fork. op is the original bolt, tmp
112 * is the first piece of the fork. 110 * is the first piece of the fork.
113 */ 111 */
114
115void 112void
116forklightning (object *op, object *tmp) 113forklightning (object *op, object *tmp)
117{ 114{
118 int new_dir = 1; /* direction or -1 for left, +1 for right 0 if no new bolt */ 115 int new_dir = 1; /* direction or -1 for left, +1 for right 0 if no new bolt */
119 int t_dir; /* stores temporary dir calculation */ 116 int t_dir; /* stores temporary dir calculation */
151 new_bolt->duration++; 148 new_bolt->duration++;
152 new_bolt->stats.dam /= 2; /* reduce daughter bolt damage */ 149 new_bolt->stats.dam /= 2; /* reduce daughter bolt damage */
153 new_bolt->stats.dam++; 150 new_bolt->stats.dam++;
154 tmp->stats.dam /= 2; /* reduce father bolt damage */ 151 tmp->stats.dam /= 2; /* reduce father bolt damage */
155 tmp->stats.dam++; 152 tmp->stats.dam++;
153
156 if ((new_bolt = m->insert (new_bolt, sx, sy, op))) 154 if ((new_bolt = m->insert (new_bolt, sx, sy, op)))
157 update_turn_face (new_bolt); 155 update_turn_face (new_bolt);
158} 156}
159 157
160/* move_bolt: moves bolt 'op'. Basically, it just advances a space, 158/* move_bolt: moves bolt 'op'. Basically, it just advances a space,
161 * and checks for various things that may stop it. 159 * and checks for various things that may stop it.
162 */ 160 */
163
164void 161void
165move_bolt (object *op) 162move_bolt (object *op)
166{ 163{
167 int mflags; 164 int mflags;
168 sint16 x, y; 165 sint16 x, y;
169 maptile *m; 166 maptile *m;
170 167
171 if (--op->duration < 0) 168 if (--op->duration < 0)
172 { 169 {
170 op->destroy_inv (true); // be explicit about dropping
173 op->destroy (); 171 op->destroy (true);
174 return; 172 return;
175 } 173 }
176 174
177 hit_map (op, 0, op->attacktype, 1); 175 hit_map (op, 0, op->attacktype, 1);
178 176
251 tmp->duration++; 249 tmp->duration++;
252 250
253 /* New forking code. Possibly create forks of this object 251 /* New forking code. Possibly create forks of this object
254 * going off in other directions. 252 * going off in other directions.
255 */ 253 */
256 if (rndm (0, 99) < tmp->stats.Dex) 254 if (tmp->stats.Dex && rndm (0, 99) < tmp->stats.Dex)
257 { /* stats.Dex % of forking */ 255 forklightning (op, tmp); /* stats.Dex % of forking */
258 forklightning (op, tmp);
259 }
260 256
261 /* In this way, the object left behind sticks on the space, but 257 /* In this way, the object left behind sticks on the space, but
262 * doesn't create any bolts that continue to move onward. 258 * doesn't create any bolts that continue to move onward.
263 */ 259 */
264 op->range = 0; 260 op->range = 0;
288 return 0; 284 return 0;
289 285
290 /* peterm: level dependency for bolts */ 286 /* peterm: level dependency for bolts */
291 tmp->stats.dam = spob->stats.dam + SP_level_dam_adjust (caster, spob); 287 tmp->stats.dam = spob->stats.dam + SP_level_dam_adjust (caster, spob);
292 tmp->attacktype = spob->attacktype; 288 tmp->attacktype = spob->attacktype;
289
293 if (spob->slaying) 290 if (spob->slaying)
294 tmp->slaying = spob->slaying; 291 tmp->slaying = spob->slaying;
292
295 tmp->range = spob->range + SP_level_range_adjust (caster, spob); 293 tmp->range = spob->range + SP_level_range_adjust (caster, spob);
296 tmp->duration = spob->duration + SP_level_duration_adjust (caster, spob); 294 tmp->duration = spob->duration + SP_level_duration_adjust (caster, spob);
297 tmp->stats.Dex = spob->stats.Dex; 295 tmp->stats.Dex = spob->stats.Dex;
298 tmp->stats.Con = spob->stats.Con; 296 tmp->stats.Con = spob->stats.Con;
299 297
310 308
311 maptile *newmap; 309 maptile *newmap;
312 mflags = get_map_flags (tmp->map, &newmap, tmp->x, tmp->y, &tmp->x, &tmp->y); 310 mflags = get_map_flags (tmp->map, &newmap, tmp->x, tmp->y, &tmp->x, &tmp->y);
313 if (mflags & P_OUT_OF_MAP) 311 if (mflags & P_OUT_OF_MAP)
314 { 312 {
313 tmp->destroy_inv (true); // be explicit about dropping
315 tmp->destroy (); 314 tmp->destroy (true);
316 return 0; 315 return 0;
317 } 316 }
318 317
319 tmp->map = newmap; 318 tmp->map = newmap;
320 319
321 if (OB_TYPE_MOVE_BLOCK (tmp, GET_MAP_MOVE_BLOCK (tmp->map, tmp->x, tmp->y))) 320 if (OB_TYPE_MOVE_BLOCK (tmp, GET_MAP_MOVE_BLOCK (tmp->map, tmp->x, tmp->y)))
322 { 321 {
323 if (!QUERY_FLAG (tmp, FLAG_REFLECTING)) 322 if (!QUERY_FLAG (tmp, FLAG_REFLECTING))
324 { 323 {
324 tmp->destroy_inv (true); // be explicit about dropping
325 tmp->destroy (); 325 tmp->destroy (true);
326 return 0; 326 return 0;
327 } 327 }
328 328
329 tmp->x = op->x; 329 tmp->x = op->x;
330 tmp->y = op->y; 330 tmp->y = op->y;
354 maptile *m = op->map; 354 maptile *m = op->map;
355 int i; 355 int i;
356 356
357 if (--op->duration < 0) 357 if (--op->duration < 0)
358 { 358 {
359 op->destroy (); 359 op->destroy (true);
360 return; 360 return;
361 } 361 }
362 362
363 hit_map (op, 0, op->attacktype, 0); 363 hit_map (op, 0, op->attacktype, 0);
364 364
396void 396void
397explode_bullet (object *op) 397explode_bullet (object *op)
398{ 398{
399 object *tmp, *owner; 399 object *tmp, *owner;
400 400
401 if (op->other_arch == NULL) 401 if (!op->other_arch)
402 { 402 {
403 LOG (llevError, "BUG: explode_bullet(): op without other_arch\n"); 403 LOG (llevError, "BUG: explode_bullet(): op without other_arch\n");
404 op->destroy (); 404 op->destroy (true);
405 return; 405 return;
406 } 406 }
407 407
408 if (op->env) 408 if (op->env)
409 { 409 {
410 object *env = op->outer_env (); 410 object *env = op->outer_env ();
411 411
412 if (!env->map || out_of_map (env->map, env->x, env->y)) 412 if (!env->map || out_of_map (env->map, env->x, env->y))
413 { 413 {
414 LOG (llevError, "BUG: explode_bullet(): env out of map\n"); 414 LOG (llevError, "BUG: explode_bullet(): env out of map\n");
415 op->destroy (); 415 op->destroy (true);
416 return; 416 return;
417 } 417 }
418 418
419 op->insert_at (env, op, INS_NO_MERGE | INS_NO_WALK_ON); 419 op->insert_at (env, op, INS_NO_MERGE | INS_NO_WALK_ON);
420 } 420 }
421 else if (out_of_map (op->map, op->x, op->y)) 421 else if (out_of_map (op->map, op->x, op->y))
422 { 422 {
423 LOG (llevError, "BUG: explode_bullet(): op out of map\n"); 423 LOG (llevError, "BUG: explode_bullet(): op out of map\n");
424 op->destroy (); 424 op->destroy (true);
425 return; 425 return;
426 } 426 }
427 427
428 // elmex Tue Aug 15 17:46:51 CEST 2006: Prevent explosions of any kind on safe maps 428 // elmex Tue Aug 15 17:46:51 CEST 2006: Prevent explosions of any kind on safe maps
429 // NOTE: If this breaks something important: remove this. I can't think of anything 429 // NOTE: If this breaks something important: remove this. I can't think of anything
430 // bad at the moment that might happen from this. 430 // bad at the moment that might happen from this.
431 if (get_map_flags (op->map, NULL, op->x, op->y, NULL, NULL) & P_SAFE) 431 if (get_map_flags (op->map, NULL, op->x, op->y, NULL, NULL) & P_SAFE)
432 { 432 {
433 op->destroy (); 433 op->destroy (true);
434 return; 434 return;
435 } 435 }
436 436
437 if (op->attacktype) 437 if (op->attacktype)
438 { 438 {
439 hit_map (op, 0, op->attacktype, 1); 439 hit_map (op, 0, op->attacktype, 1);
440
440 if (op->destroyed ()) 441 if (op->destroyed ())
441 return; 442 return;
442 } 443 }
443 444
444 /* other_arch contains what this explodes into */ 445 /* other_arch contains what this explodes into */
447 tmp->set_owner (op); 448 tmp->set_owner (op);
448 tmp->skill = op->skill; 449 tmp->skill = op->skill;
449 450
450 owner = op->owner; 451 owner = op->owner;
451 452
452 if ((tmp->attacktype & AT_HOLYWORD || tmp->attacktype & AT_GODPOWER) && owner && !tailor_god_spell (tmp, owner)) 453 if ((tmp->attacktype & AT_HOLYWORD
454 || tmp->attacktype & AT_GODPOWER)
455 && owner
456 && !tailor_god_spell (tmp, owner))
453 { 457 {
454 op->destroy (); 458 op->destroy (true);
455 return; 459 return;
456 } 460 }
457 461
458 /* special for bombs - it actually has sane values for these */ 462 /* special for bombs - it actually has sane values for these */
459 if (op->type == SPELL_EFFECT && op->subtype == SP_BOMB) 463 if (op->type == SPELL_EFFECT && op->subtype == SP_BOMB)
487 491
488 tmp->insert_at (op, op); 492 tmp->insert_at (op, op);
489 tmp->play_sound (tmp->sound); 493 tmp->play_sound (tmp->sound);
490 494
491 /* remove the firebullet */ 495 /* remove the firebullet */
492 op->destroy (); 496 op->destroy (true);
493} 497}
494 498
495/* checks to see what op should do, given the space it is on 499/* checks to see what op should do, given the space it is on
496 * (eg, explode, damage player, etc) 500 * (eg, explode, damage player, etc)
497 */ 501 */
522 for (tmp = op->ms ().bot; tmp; tmp = tmp->above) 526 for (tmp = op->ms ().bot; tmp; tmp = tmp->above)
523 { 527 {
524 if (QUERY_FLAG (tmp, FLAG_ALIVE)) 528 if (QUERY_FLAG (tmp, FLAG_ALIVE))
525 { 529 {
526 dam = hit_player (tmp, op->stats.dam, op, op->attacktype, 1); 530 dam = hit_player (tmp, op->stats.dam, op, op->attacktype, 1);
531
532 // TODO: can't understand the following if's
527 if (op->destroyed () || !tmp->destroyed () || (op->stats.dam -= dam) < 0) 533 if (op->destroyed () || !tmp->destroyed () || (op->stats.dam -= dam) < 0)
528 { 534 {
529 if (!QUERY_FLAG (op, FLAG_REMOVED)) 535 if (!QUERY_FLAG (op, FLAG_REMOVED))
530 { 536 {
531 op->destroy (); 537 op->destroy (true);
532 return; 538 return;
533 } 539 }
534 } 540 }
535 } 541 }
536 } 542 }
565 if (--op->range <= 0) 571 if (--op->range <= 0)
566 { 572 {
567 if (op->other_arch) 573 if (op->other_arch)
568 explode_bullet (op); 574 explode_bullet (op);
569 else 575 else
570 op->destroy (); 576 op->destroy (true);
571 577
572 return; 578 return;
573 } 579 }
574 580
575 new_x = op->x + DIRX (op); 581 new_x = op->x + DIRX (op);
577 m = op->map; 583 m = op->map;
578 mflags = get_map_flags (m, &m, new_x, new_y, &new_x, &new_y); 584 mflags = get_map_flags (m, &m, new_x, new_y, &new_x, &new_y);
579 585
580 if (mflags & P_OUT_OF_MAP) 586 if (mflags & P_OUT_OF_MAP)
581 { 587 {
582 op->destroy (); 588 op->destroy (true);
583 return; 589 return;
584 } 590 }
585 591
586 if (!op->direction || OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, new_x, new_y))) 592 if (!op->direction || OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, new_x, new_y)))
587 { 593 {
588 if (op->other_arch) 594 if (op->other_arch)
589 explode_bullet (op); 595 explode_bullet (op);
590 else 596 else
591 op->destroy (); 597 op->destroy (true);
592 598
593 return; 599 return;
594 } 600 }
595 601
596 if (!(op = m->insert (op, new_x, new_y, op))) 602 if (!(op = m->insert (op, new_x, new_y, op)))
652 658
653 maptile *newmap; 659 maptile *newmap;
654 mflags = get_map_flags (tmp->map, &newmap, tmp->x, tmp->y, &tmp->x, &tmp->y); 660 mflags = get_map_flags (tmp->map, &newmap, tmp->x, tmp->y, &tmp->x, &tmp->y);
655 if (mflags & P_OUT_OF_MAP) 661 if (mflags & P_OUT_OF_MAP)
656 { 662 {
657 tmp->destroy (); 663 tmp->destroy (true);
658 return 0; 664 return 0;
659 } 665 }
660 666
661 tmp->map = newmap; 667 tmp->map = newmap;
662 668
663 if (OB_TYPE_MOVE_BLOCK (tmp, GET_MAP_MOVE_BLOCK (tmp->map, tmp->x, tmp->y))) 669 if (OB_TYPE_MOVE_BLOCK (tmp, GET_MAP_MOVE_BLOCK (tmp->map, tmp->x, tmp->y)))
664 { 670 {
665 if (!QUERY_FLAG (tmp, FLAG_REFLECTING)) 671 if (!QUERY_FLAG (tmp, FLAG_REFLECTING))
666 { 672 {
667 tmp->destroy (); 673 tmp->destroy (true);
668 return 0; 674 return 0;
669 } 675 }
670 676
671 tmp->x = op->x; 677 tmp->x = op->x;
672 tmp->y = op->y; 678 tmp->y = op->y;
705/* move_cone: causes cone object 'op' to move a space/hit creatures */ 711/* move_cone: causes cone object 'op' to move a space/hit creatures */
706 712
707void 713void
708move_cone (object *op) 714move_cone (object *op)
709{ 715{
710 int i;
711
712 /* if no map then hit_map will crash so just ignore object */ 716 /* if no map then hit_map will crash so just ignore object */
713 if (!op->map) 717 if (!op->map)
714 { 718 {
715 LOG (llevError, "Tried to move_cone object %s without a map.\n", op->name ? &op->name : "unknown"); 719 LOG (llevError, "Tried to move_cone object %s without a map.\n", op->name ? &op->name : "unknown");
716 op->set_speed (0); 720 op->set_speed (0);
729 * when their cone dies when they die. 733 * when their cone dies when they die.
730 */ 734 */
731 /* If no owner left, the spell dies out. */ 735 /* If no owner left, the spell dies out. */
732 if (op->owner == NULL) 736 if (op->owner == NULL)
733 { 737 {
734 op->destroy (); 738 op->destroy (true);
735 return; 739 return;
736 } 740 }
737#endif 741#endif
738 742
739 hit_map (op, 0, op->attacktype, 0); 743 hit_map (op, 0, op->attacktype, 0);
746 check_spell_knockback (op); 750 check_spell_knockback (op);
747 751
748 if (op->destroyed ()) 752 if (op->destroyed ())
749 return; 753 return;
750 754
751 if ((op->duration--) < 0) 755 if (op->duration-- < 0)
752 { 756 {
753 op->destroy (); 757 op->destroy (true);
754 return; 758 return;
755 } 759 }
756 /* Object has hit maximum range, so don't have it move 760 /* Object has hit maximum range, so don't have it move
757 * any further. When the duration above expires, 761 * any further. When the duration above expires,
758 * then the object will get removed. 762 * then the object will get removed.
761 { 765 {
762 op->range = 0; /* just so it doesn't wrap */ 766 op->range = 0; /* just so it doesn't wrap */
763 return; 767 return;
764 } 768 }
765 769
766 for (i = -1; i < 2; i++) 770 for (int i = -1; i <= 1; i++)
767 { 771 {
768 sint16 x = op->x + freearr_x[absdir (op->stats.sp + i)], y = op->y + freearr_y[absdir (op->stats.sp + i)]; 772 sint16 x = op->x + freearr_x[absdir (op->stats.sp + i)], y = op->y + freearr_y[absdir (op->stats.sp + i)];
769 773
770 if (ok_to_put_more (op->map, x, y, op, op->attacktype)) 774 if (ok_to_put_more (op->map, x, y, op, op->attacktype))
771 { 775 {
863 867
864 success = 1; 868 success = 1;
865 tmp = arch_to_object (spell->other_arch); 869 tmp = arch_to_object (spell->other_arch);
866 tmp->set_owner (op); 870 tmp->set_owner (op);
867 set_spell_skill (op, caster, spell, tmp); 871 set_spell_skill (op, caster, spell, tmp);
868 tmp->level = caster_level (caster, spell); 872 tmp->level = casting_level (caster, spell);
869 tmp->attacktype = spell->attacktype; 873 tmp->attacktype = spell->attacktype;
870 874
871 /* holy word stuff */ 875 /* holy word stuff */
872 if ((tmp->attacktype & AT_HOLYWORD) || (tmp->attacktype & AT_GODPOWER)) 876 if ((tmp->attacktype & AT_HOLYWORD) || (tmp->attacktype & AT_GODPOWER))
873 if (!tailor_god_spell (tmp, op)) 877 if (!tailor_god_spell (tmp, op))
957 // elmex Tue Aug 15 17:46:51 CEST 2006: Prevent bomb from exploding 961 // elmex Tue Aug 15 17:46:51 CEST 2006: Prevent bomb from exploding
958 // on a safe map. I don't like this special casing, but it seems to be neccessary 962 // on a safe map. I don't like this special casing, but it seems to be neccessary
959 // as bombs can be carried. 963 // as bombs can be carried.
960 if (get_map_flags (op->map, NULL, op->x, op->y, NULL, NULL) & P_SAFE) 964 if (get_map_flags (op->map, NULL, op->x, op->y, NULL, NULL) & P_SAFE)
961 { 965 {
962 op->destroy (); 966 op->destroy (true);
963 return; 967 return;
964 } 968 }
965 969
966 /* This copies a lot of the code from the fire bullet, 970 /* This copies a lot of the code from the fire bullet,
967 * but using the cast_bullet isn't really feasible, 971 * but using the cast_bullet isn't really feasible,
1115 effect = arch_to_object (spell->other_arch); 1119 effect = arch_to_object (spell->other_arch);
1116 else 1120 else
1117 return 0; 1121 return 0;
1118 1122
1119 /* tailor the effect by priest level and worshipped God */ 1123 /* tailor the effect by priest level and worshipped God */
1120 effect->level = caster_level (caster, spell); 1124 effect->level = casting_level (caster, spell);
1121 effect->attacktype = spell->attacktype; 1125 effect->attacktype = spell->attacktype;
1122 if (effect->attacktype & (AT_HOLYWORD | AT_GODPOWER)) 1126 if (effect->attacktype & (AT_HOLYWORD | AT_GODPOWER))
1123 { 1127 {
1124 if (tailor_god_spell (effect, op)) 1128 if (tailor_god_spell (effect, op))
1125 new_draw_info_format (NDI_UNIQUE, 0, op, "%s answers your call!", determine_god (op)); 1129 new_draw_info_format (NDI_UNIQUE, 0, op, "%s answers your call!", determine_god (op));
1149 } 1153 }
1150 else 1154 else
1151 { 1155 {
1152 new_draw_info_format (NDI_UNIQUE, 0, op, "The %s looks stronger!", query_name (target)); 1156 new_draw_info_format (NDI_UNIQUE, 0, op, "The %s looks stronger!", query_name (target));
1153 target->stats.hp = target->stats.maxhp * 2; 1157 target->stats.hp = target->stats.maxhp * 2;
1154 effect->destroy (); 1158 effect->destroy (true);
1155 return 0; 1159 return 0;
1156 } 1160 }
1157 } 1161 }
1158 } 1162 }
1159 else 1163 else
1180 1184
1181/* op is a missile that needs to be moved */ 1185/* op is a missile that needs to be moved */
1182void 1186void
1183move_missile (object *op) 1187move_missile (object *op)
1184{ 1188{
1185 int i, mflags;
1186 object *owner;
1187 sint16 new_x, new_y;
1188 maptile *m;
1189
1190 if (op->range-- <= 0) 1189 if (op->range-- <= 0)
1191 { 1190 {
1191 op->destroy_inv (true); // be explicit about dropping
1192 op->destroy (); 1192 op->destroy (true);
1193 return; 1193 return;
1194 }
1195
1196 owner = op->owner;
1197#if 0
1198 /* It'd make things nastier if this wasn't here - spells cast by
1199 * monster that are then killed would continue to survive
1200 */
1201 if (owner == NULL)
1202 { 1194 }
1195
1196 mapxy pos (op);
1197 pos.move (op->direction);
1198
1199 if (!pos.normalise ())
1200 {
1203 op->destroy (); 1201 op->destroy (true);
1204 return; 1202 return;
1205 } 1203 }
1206#endif
1207 1204
1208 new_x = op->x + DIRX (op); 1205 mapspace &ms = pos.ms ();
1209 new_y = op->y + DIRY (op);
1210 1206
1211 mflags = get_map_flags (op->map, &m, new_x, new_y, &new_x, &new_y); 1207 if (ms.flags () & P_IS_ALIVE || ms.blocks (op))
1212
1213 if (!(mflags & P_OUT_OF_MAP) && ((mflags & P_IS_ALIVE) || OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, new_x, new_y))))
1214 { 1208 {
1215 hit_map (op, op->direction, AT_MAGIC, 1); 1209 hit_map (op, op->direction, AT_MAGIC, 1);
1216 /* Basically, missile only hits one thing then goes away. 1210 /* Basically, missile only hits one thing then goes away.
1217 * we need to remove it if someone hasn't already done so. 1211 * we need to remove it if someone hasn't already done so.
1218 */ 1212 */
1219 if (!op->destroyed ())
1220 op->destroy ();
1221
1222 return;
1223 }
1224
1225 op->remove ();
1226
1227 if (!op->direction || (mflags & P_OUT_OF_MAP))
1228 {
1229 op->destroy (); 1213 op->destroy (true);
1230 return; 1214 return;
1215 }
1216
1217 if (!op->direction)
1231 } 1218 {
1219 op->destroy (true);
1220 return;
1221 }
1232 1222
1233 i = spell_find_dir (m, new_x, new_y, op->owner); 1223 int i = spell_find_dir (pos.m, pos.x, pos.y, op->owner);
1234 if (i > 0 && i != op->direction) 1224 if (i > 0 && i != op->direction)
1235 { 1225 {
1236 op->direction = i; 1226 op->direction = i;
1237 SET_ANIMATION (op, op->direction); 1227 SET_ANIMATION (op, op->direction);
1238 } 1228 }
1239 1229
1240 m->insert (op, new_x, new_y, op); 1230 pos.insert (op, op);
1241} 1231}
1242 1232
1243/**************************************************************************** 1233/****************************************************************************
1244 * Destruction 1234 * Destruction
1245 ****************************************************************************/ 1235 ****************************************************************************/
1302 else 1292 else
1303 op->skill = NULL; 1293 op->skill = NULL;
1304 1294
1305 op->change_skill (find_skill_by_name (op, op->skill)); 1295 op->change_skill (find_skill_by_name (op, op->skill));
1306 1296
1307 for (i = -range; i < range; i++) 1297 for (i = -range; i <= range; i++)
1308 { 1298 {
1309 for (j = -range; j < range; j++) 1299 for (j = -range; j <= range; j++)
1310 { 1300 {
1311 m = op->map; 1301 m = op->map;
1312 sx = op->x + i; 1302 sx = op->x + i;
1313 sy = op->y + j; 1303 sy = op->y + j;
1314 1304
1331 (!friendly && (QUERY_FLAG (tmp, FLAG_FRIENDLY) || tmp->type == PLAYER))) 1321 (!friendly && (QUERY_FLAG (tmp, FLAG_FRIENDLY) || tmp->type == PLAYER)))
1332 { 1322 {
1333 if (spell_ob->subtype == SP_DESTRUCTION) 1323 if (spell_ob->subtype == SP_DESTRUCTION)
1334 { 1324 {
1335 hit_player (tmp, dam, op, spell_ob->attacktype, 0); 1325 hit_player (tmp, dam, op, spell_ob->attacktype, 0);
1326
1336 if (spell_ob->other_arch) 1327 if (spell_ob->other_arch)
1337 m->insert (arch_to_object (spell_ob->other_arch), sx, sy, op); 1328 m->insert (arch_to_object (spell_ob->other_arch), sx, sy, op);
1338 } 1329 }
1339 else if (spell_ob->subtype == SP_FAERY_FIRE && tmp->resist[ATNR_MAGIC] != 100) 1330 else if (spell_ob->subtype == SP_FAERY_FIRE && tmp->resist[ATNR_MAGIC] != 100)
1340 { 1331 {
1468 1459
1469 /* We precompute some values here so that we don't have to keep 1460 /* We precompute some values here so that we don't have to keep
1470 * doing it over and over again. 1461 * doing it over and over again.
1471 */ 1462 */
1472 god = find_god (determine_god (op)); 1463 god = find_god (determine_god (op));
1473 level = caster_level (caster, spell); 1464 level = casting_level (caster, spell);
1474 range = spell->range + SP_level_range_adjust (caster, spell); 1465 range = spell->range + SP_level_range_adjust (caster, spell);
1475 1466
1476 /* On the bright side, no monster should ever have a race of GOD_... 1467 /* On the bright side, no monster should ever have a race of GOD_...
1477 * so even if the player doesn't worship a god, if race=GOD_.., it 1468 * so even if the player doesn't worship a god, if race=GOD_.., it
1478 * won't ever match anything. 1469 * won't ever match anything.
1628 * about. was called move_ball_lightning, but since more than the ball 1619 * about. was called move_ball_lightning, but since more than the ball
1629 * lightning spell used it, that seemed misnamed. 1620 * lightning spell used it, that seemed misnamed.
1630 * op is the spell effect. 1621 * op is the spell effect.
1631 * note that duration is handled by process_object() in time.c 1622 * note that duration is handled by process_object() in time.c
1632 */ 1623 */
1633
1634void 1624void
1635move_ball_spell (object *op) 1625move_ball_spell (object *op)
1636{ 1626{
1637 int i, j, dam_save, dir, mflags; 1627 int i, j, dam_save, dir, mflags;
1638 sint16 nx, ny, hx, hy; 1628 sint16 nx, ny, hx, hy;
1704 1694
1705 if ((mflags & P_IS_ALIVE) && (!owner || owner->x != hx || owner->y != hy || !on_same_map (owner, op))) 1695 if ((mflags & P_IS_ALIVE) && (!owner || owner->x != hx || owner->y != hy || !on_same_map (owner, op)))
1706 { 1696 {
1707 if (j) 1697 if (j)
1708 op->stats.dam = dam_save / 2; 1698 op->stats.dam = dam_save / 2;
1699
1709 hit_map (op, j, op->attacktype, 1); 1700 hit_map (op, j, op->attacktype, 1);
1710
1711 } 1701 }
1712 1702
1713 /* insert the other arch */ 1703 /* insert the other arch */
1714 if (op->other_arch && !(OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, hx, hy)))) 1704 if (op->other_arch && !(OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, hx, hy))))
1715 m->insert (arch_to_object (op->other_arch), hx, hy, op); 1705 m->insert (arch_to_object (op->other_arch), hx, hy, op);
1748 int adjustdir; 1738 int adjustdir;
1749 maptile *m; 1739 maptile *m;
1750#endif 1740#endif
1751 object *owner = op->env; 1741 object *owner = op->env;
1752 1742
1743 if (!owner) // MUST not happen, remove when true TODO
1744 {
1745 LOG (llevError, "swarm spell found outside inventory: %s\n", op->debug_desc ());
1746 op->destroy (true);
1747 return;
1748 }
1749
1753 if (!op->duration || !owner->is_on_map ()) 1750 if (!op->duration || !owner->is_on_map ())
1754 { 1751 {
1752 op->destroy_inv (true); // be explicit about dropping
1755 op->destroy (); 1753 op->destroy (true);
1756 return; 1754 return;
1757 } 1755 }
1758 1756
1759 op->duration--; 1757 op->duration--;
1760 1758
1761 int basedir = op->direction; 1759 int basedir = op->direction;
1762 if (!basedir) 1760 if (!basedir)
1761 {
1763 /* spray in all directions! 8) */ 1762 /* spray in all directions! 8) */
1764 basedir = rndm (1, 8); 1763 op->facing = (op->facing + op->state) & 7;
1764 basedir = op->facing + 1;
1765 }
1765 1766
1766#if 0 1767#if 0
1767 // this is bogus: it causes wrong places to be checked below 1768 // this is bogus: it causes wrong places to be checked below
1768 // (a wall 2 cells away will block the effect...) and 1769 // (a wall 2 cells away will block the effect...) and
1769 // doesn't work for SP_BULLET anyhow, so again tests the wrong 1770 // doesn't work for SP_BULLET anyhow, so again tests the wrong
1829 { 1830 {
1830 /* Bullet spells have a bunch more customization that needs to be done */ 1831 /* Bullet spells have a bunch more customization that needs to be done */
1831 if (op->spell->subtype == SP_BULLET) 1832 if (op->spell->subtype == SP_BULLET)
1832 fire_bullet (owner, op, basedir, op->spell); 1833 fire_bullet (owner, op, basedir, op->spell);
1833 else if (op->spell->subtype == SP_MAGIC_MISSILE) 1834 else if (op->spell->subtype == SP_MAGIC_MISSILE)
1834 fire_arch_from_position (owner, op, op->x, op->y, basedir, op->spell); 1835 fire_arch_from_position (owner, op, owner->x, owner->y, basedir, op->spell);
1835 } 1836 }
1836} 1837}
1837 1838
1838/* fire_swarm: 1839/* fire_swarm:
1839 * The following routine creates a swarm of objects. It actually 1840 * The following routine creates a swarm of objects. It actually
1851{ 1852{
1852 if (!spell->other_arch) 1853 if (!spell->other_arch)
1853 return 0; 1854 return 0;
1854 1855
1855 object *tmp = archetype::get (SWARM_SPELL); 1856 object *tmp = archetype::get (SWARM_SPELL);
1857
1856 set_spell_skill (op, caster, spell, tmp); 1858 set_spell_skill (op, caster, spell, tmp);
1857 tmp->level = caster_level (caster, spell); /* needed later, to get level dep. right. */ 1859 tmp->level = casting_level (caster, spell); /* needed later, to get level dep. right. */
1858 tmp->spell = spell->other_arch->instance (); 1860 tmp->spell = spell->other_arch->instance ();
1859 tmp->attacktype = tmp->spell->attacktype; 1861 tmp->attacktype = tmp->spell->attacktype;
1860 1862
1861 if (tmp->attacktype & AT_HOLYWORD || tmp->attacktype & AT_GODPOWER) 1863 if (tmp->attacktype & AT_HOLYWORD || tmp->attacktype & AT_GODPOWER)
1862 if (!tailor_god_spell (tmp, op)) 1864 if (!tailor_god_spell (tmp, op))
1864 1866
1865 tmp->duration = SP_level_duration_adjust (caster, spell); 1867 tmp->duration = SP_level_duration_adjust (caster, spell);
1866 for (int i = 0; i < spell->duration; i++) 1868 for (int i = 0; i < spell->duration; i++)
1867 tmp->duration += die_roll (1, 3, op, PREFER_HIGH); 1869 tmp->duration += die_roll (1, 3, op, PREFER_HIGH);
1868 1870
1871 tmp->invisible = 1;
1872 tmp->flag [FLAG_NO_DROP] = 1; // make sure it stays in inv, or else
1869 tmp->direction = dir; 1873 tmp->direction = dir;
1870 tmp->invisible = 1; 1874 tmp->facing = rndm (1, 8); // initial firing direction
1875 tmp->state = rndm (4) * 2 + 1; // direction increment
1871 1876
1872 op->insert (tmp); 1877 op->insert (tmp);
1873 1878
1874 return 1; 1879 return 1;
1875} 1880}
1911 if (QUERY_FLAG (target, FLAG_MONSTER)) 1916 if (QUERY_FLAG (target, FLAG_MONSTER))
1912 { 1917 {
1913 /* oky doky. got a target monster. Lets make a blinding attack */ 1918 /* oky doky. got a target monster. Lets make a blinding attack */
1914 if (target->head) 1919 if (target->head)
1915 target = target->head; 1920 target = target->head;
1921
1916 (void) hit_player (target, dam, op, spell->attacktype, 1); 1922 hit_player (target, dam, op, spell->attacktype, 1);
1917 return 1; /* one success only! */ 1923 return 1; /* one success only! */
1918 } 1924 }
1919 } 1925 }
1920 1926
1921 /* no live target, perhaps a wall is in the way? */ 1927 /* no live target, perhaps a wall is in the way? */
2001 object *disease = arch_to_object (spell->other_arch); 2007 object *disease = arch_to_object (spell->other_arch);
2002 2008
2003 disease->set_owner (op); 2009 disease->set_owner (op);
2004 set_spell_skill (op, caster, spell, disease); 2010 set_spell_skill (op, caster, spell, disease);
2005 disease->stats.exp = 0; 2011 disease->stats.exp = 0;
2006 disease->level = caster_level (caster, spell); 2012 disease->level = casting_level (caster, spell);
2007 2013
2008 /* do level adjustments */ 2014 /* do level adjustments */
2009 if (disease->stats.wc) 2015 if (disease->stats.wc)
2010 disease->stats.wc += dur_mod / 2; 2016 disease->stats.wc += dur_mod / 2;
2011 2017
2055 2061
2056 if (infect_object (walk, disease, 1)) 2062 if (infect_object (walk, disease, 1))
2057 { 2063 {
2058 new_draw_info_format (NDI_UNIQUE, 0, op, "You inflict %s on %s!", &disease->name, &walk->name); 2064 new_draw_info_format (NDI_UNIQUE, 0, op, "You inflict %s on %s!", &disease->name, &walk->name);
2059 2065
2060 disease->destroy (); /* don't need this one anymore */ 2066 disease->destroy (true); /* don't need this one anymore */
2061 walk->map->insert (get_archetype ("detect_magic"), x, y, op); 2067 walk->map->insert (get_archetype ("detect_magic"), x, y, op);
2062 return 1; 2068 return 1;
2063 } 2069 }
2064 2070
2065 disease->destroy (); 2071 disease->destroy (true);
2066 } 2072 }
2067 } /* if living creature */ 2073 } /* if living creature */
2068 } /* for range of spaces */ 2074 } /* for range of spaces */
2069 2075
2070 new_draw_info (NDI_UNIQUE, 0, op, "No one caught anything!"); 2076 new_draw_info (NDI_UNIQUE, 0, op, "No one caught anything!");

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines