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.54 by root, Wed Apr 30 10:31:04 2008 UTC vs.
Revision 1.72 by root, Sat Dec 27 08:01:07 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 {
173 op->destroy (); 170 op->drop_and_destroy ();
174 return; 171 return;
175 } 172 }
176 173
177 hit_map (op, 0, op->attacktype, 1); 174 hit_map (op, 0, op->attacktype, 1);
178 175
251 tmp->duration++; 248 tmp->duration++;
252 249
253 /* New forking code. Possibly create forks of this object 250 /* New forking code. Possibly create forks of this object
254 * going off in other directions. 251 * going off in other directions.
255 */ 252 */
256 if (rndm (0, 99) < tmp->stats.Dex) 253 if (tmp->stats.Dex && rndm (0, 99) < tmp->stats.Dex)
257 { /* stats.Dex % of forking */ 254 forklightning (op, tmp); /* stats.Dex % of forking */
258 forklightning (op, tmp);
259 }
260 255
261 /* In this way, the object left behind sticks on the space, but 256 /* In this way, the object left behind sticks on the space, but
262 * doesn't create any bolts that continue to move onward. 257 * doesn't create any bolts that continue to move onward.
263 */ 258 */
264 op->range = 0; 259 op->range = 0;
288 return 0; 283 return 0;
289 284
290 /* peterm: level dependency for bolts */ 285 /* peterm: level dependency for bolts */
291 tmp->stats.dam = spob->stats.dam + SP_level_dam_adjust (caster, spob); 286 tmp->stats.dam = spob->stats.dam + SP_level_dam_adjust (caster, spob);
292 tmp->attacktype = spob->attacktype; 287 tmp->attacktype = spob->attacktype;
288
293 if (spob->slaying) 289 if (spob->slaying)
294 tmp->slaying = spob->slaying; 290 tmp->slaying = spob->slaying;
291
295 tmp->range = spob->range + SP_level_range_adjust (caster, spob); 292 tmp->range = spob->range + SP_level_range_adjust (caster, spob);
296 tmp->duration = spob->duration + SP_level_duration_adjust (caster, spob); 293 tmp->duration = spob->duration + SP_level_duration_adjust (caster, spob);
297 tmp->stats.Dex = spob->stats.Dex; 294 tmp->stats.Dex = spob->stats.Dex;
298 tmp->stats.Con = spob->stats.Con; 295 tmp->stats.Con = spob->stats.Con;
299 296
310 307
311 maptile *newmap; 308 maptile *newmap;
312 mflags = get_map_flags (tmp->map, &newmap, tmp->x, tmp->y, &tmp->x, &tmp->y); 309 mflags = get_map_flags (tmp->map, &newmap, tmp->x, tmp->y, &tmp->x, &tmp->y);
313 if (mflags & P_OUT_OF_MAP) 310 if (mflags & P_OUT_OF_MAP)
314 { 311 {
315 tmp->destroy (); 312 tmp->drop_and_destroy ();
316 return 0; 313 return 0;
317 } 314 }
318 315
319 tmp->map = newmap; 316 tmp->map = newmap;
320 317
321 if (OB_TYPE_MOVE_BLOCK (tmp, GET_MAP_MOVE_BLOCK (tmp->map, tmp->x, tmp->y))) 318 if (OB_TYPE_MOVE_BLOCK (tmp, GET_MAP_MOVE_BLOCK (tmp->map, tmp->x, tmp->y)))
322 { 319 {
323 if (!QUERY_FLAG (tmp, FLAG_REFLECTING)) 320 if (!QUERY_FLAG (tmp, FLAG_REFLECTING))
324 { 321 {
325 tmp->destroy (); 322 tmp->drop_and_destroy ();
326 return 0; 323 return 0;
327 } 324 }
328 325
329 tmp->x = op->x; 326 tmp->x = op->x;
330 tmp->y = op->y; 327 tmp->y = op->y;
396void 393void
397explode_bullet (object *op) 394explode_bullet (object *op)
398{ 395{
399 object *tmp, *owner; 396 object *tmp, *owner;
400 397
401 if (op->other_arch == NULL) 398 if (!op->other_arch)
402 { 399 {
403 LOG (llevError, "BUG: explode_bullet(): op without other_arch\n"); 400 LOG (llevError, "BUG: explode_bullet(): op without other_arch\n");
404 op->destroy (); 401 op->destroy ();
405 return; 402 return;
406 } 403 }
435 } 432 }
436 433
437 if (op->attacktype) 434 if (op->attacktype)
438 { 435 {
439 hit_map (op, 0, op->attacktype, 1); 436 hit_map (op, 0, op->attacktype, 1);
437
440 if (op->destroyed ()) 438 if (op->destroyed ())
441 return; 439 return;
442 } 440 }
443 441
444 /* other_arch contains what this explodes into */ 442 /* other_arch contains what this explodes into */
447 tmp->set_owner (op); 445 tmp->set_owner (op);
448 tmp->skill = op->skill; 446 tmp->skill = op->skill;
449 447
450 owner = op->owner; 448 owner = op->owner;
451 449
452 if ((tmp->attacktype & AT_HOLYWORD || tmp->attacktype & AT_GODPOWER) && owner && !tailor_god_spell (tmp, owner)) 450 if ((tmp->attacktype & AT_HOLYWORD
451 || tmp->attacktype & AT_GODPOWER)
452 && owner
453 && !tailor_god_spell (tmp, owner))
453 { 454 {
454 op->destroy (); 455 op->destroy ();
455 return; 456 return;
456 } 457 }
457 458
522 for (tmp = op->ms ().bot; tmp; tmp = tmp->above) 523 for (tmp = op->ms ().bot; tmp; tmp = tmp->above)
523 { 524 {
524 if (QUERY_FLAG (tmp, FLAG_ALIVE)) 525 if (QUERY_FLAG (tmp, FLAG_ALIVE))
525 { 526 {
526 dam = hit_player (tmp, op->stats.dam, op, op->attacktype, 1); 527 dam = hit_player (tmp, op->stats.dam, op, op->attacktype, 1);
528
529 // TODO: can't understand the following if's
527 if (op->destroyed () || !tmp->destroyed () || (op->stats.dam -= dam) < 0) 530 if (op->destroyed () || !tmp->destroyed () || (op->stats.dam -= dam) < 0)
528 { 531 {
529 if (!QUERY_FLAG (op, FLAG_REMOVED)) 532 if (!QUERY_FLAG (op, FLAG_REMOVED))
530 { 533 {
531 op->destroy (); 534 op->destroy ();
620 int mflags; 623 int mflags;
621 624
622 if (!spob->other_arch) 625 if (!spob->other_arch)
623 return 0; 626 return 0;
624 627
625 tmp = arch_to_object (spob->other_arch); 628 tmp = spob->other_arch->instance ();
626 if (tmp == NULL) 629 if (!tmp)
627 return 0; 630 return 0;
628 631
629 /* peterm: level dependency for bolts */ 632 /* peterm: level dependency for bolts */
630 tmp->stats.dam = spob->stats.dam + SP_level_dam_adjust (caster, spob); 633 tmp->stats.dam = spob->stats.dam + SP_level_dam_adjust (caster, spob);
631 tmp->attacktype = spob->attacktype; 634 tmp->attacktype = spob->attacktype;
632 if (spob->slaying) 635 if (spob->slaying)
633 tmp->slaying = spob->slaying; 636 tmp->slaying = spob->slaying;
634 637
644 SET_ANIMATION (tmp, dir); 647 SET_ANIMATION (tmp, dir);
645 648
646 tmp->set_owner (op); 649 tmp->set_owner (op);
647 set_spell_skill (op, caster, spob, tmp); 650 set_spell_skill (op, caster, spob, tmp);
648 651
649 tmp->x = op->x + freearr_x[dir]; 652 tmp->x = op->x + freearr_x[dir];
650 tmp->y = op->y + freearr_y[dir]; 653 tmp->y = op->y + freearr_y[dir];
651 tmp->map = op->map; 654 tmp->map = op->map;
652 655
653 maptile *newmap; 656 maptile *newmap;
654 mflags = get_map_flags (tmp->map, &newmap, tmp->x, tmp->y, &tmp->x, &tmp->y); 657 mflags = get_map_flags (tmp->map, &newmap, tmp->x, tmp->y, &tmp->x, &tmp->y);
655 if (mflags & P_OUT_OF_MAP) 658 if (mflags & P_OUT_OF_MAP)
705/* move_cone: causes cone object 'op' to move a space/hit creatures */ 708/* move_cone: causes cone object 'op' to move a space/hit creatures */
706 709
707void 710void
708move_cone (object *op) 711move_cone (object *op)
709{ 712{
710 int i;
711
712 /* if no map then hit_map will crash so just ignore object */ 713 /* if no map then hit_map will crash so just ignore object */
713 if (!op->map) 714 if (!op->map)
714 { 715 {
715 LOG (llevError, "Tried to move_cone object %s without a map.\n", op->name ? &op->name : "unknown"); 716 LOG (llevError, "Tried to move_cone object %s without a map.\n", op->name ? &op->name : "unknown");
716 op->set_speed (0); 717 op->set_speed (0);
736 } 737 }
737#endif 738#endif
738 739
739 hit_map (op, 0, op->attacktype, 0); 740 hit_map (op, 0, op->attacktype, 0);
740 741
742 if (!op->is_on_map ())
743 return;
744
741 /* Check to see if we should push anything. 745 /* Check to see if we should push anything.
742 * Spell objects with weight push whatever they encounter to some 746 * Spell objects with weight push whatever they encounter to some
743 * degree. 747 * degree.
744 */ 748 */
745 if (op->weight) 749 if (op->weight)
750 {
746 check_spell_knockback (op); 751 check_spell_knockback (op);
747 752
748 if (op->destroyed ()) 753 if (!op->is_on_map ())
749 return; 754 return;
755 }
750 756
751 if ((op->duration--) < 0) 757 if (op->duration-- < 0)
752 { 758 {
753 op->destroy (); 759 op->destroy ();
754 return; 760 return;
755 } 761 }
756 /* Object has hit maximum range, so don't have it move 762 /* Object has hit maximum range, so don't have it move
761 { 767 {
762 op->range = 0; /* just so it doesn't wrap */ 768 op->range = 0; /* just so it doesn't wrap */
763 return; 769 return;
764 } 770 }
765 771
766 for (i = -1; i < 2; i++) 772 for (int i = -1; i <= 1; i++)
767 { 773 {
768 sint16 x = op->x + freearr_x[absdir (op->stats.sp + i)], y = op->y + freearr_y[absdir (op->stats.sp + i)]; 774 sint16 x = op->x + freearr_x[absdir (op->stats.sp + i)], y = op->y + freearr_y[absdir (op->stats.sp + i)];
769 775
770 if (ok_to_put_more (op->map, x, y, op, op->attacktype)) 776 if (ok_to_put_more (op->map, x, y, op, op->attacktype))
771 { 777 {
863 869
864 success = 1; 870 success = 1;
865 tmp = arch_to_object (spell->other_arch); 871 tmp = arch_to_object (spell->other_arch);
866 tmp->set_owner (op); 872 tmp->set_owner (op);
867 set_spell_skill (op, caster, spell, tmp); 873 set_spell_skill (op, caster, spell, tmp);
868 tmp->level = caster_level (caster, spell); 874 tmp->level = casting_level (caster, spell);
869 tmp->attacktype = spell->attacktype; 875 tmp->attacktype = spell->attacktype;
870 876
871 /* holy word stuff */ 877 /* holy word stuff */
872 if ((tmp->attacktype & AT_HOLYWORD) || (tmp->attacktype & AT_GODPOWER)) 878 if ((tmp->attacktype & AT_HOLYWORD) || (tmp->attacktype & AT_GODPOWER))
873 if (!tailor_god_spell (tmp, op)) 879 if (!tailor_god_spell (tmp, op))
1002 int mflags; 1008 int mflags;
1003 sint16 dx = op->x + freearr_x[dir], dy = op->y + freearr_y[dir]; 1009 sint16 dx = op->x + freearr_x[dir], dy = op->y + freearr_y[dir];
1004 maptile *m; 1010 maptile *m;
1005 1011
1006 mflags = get_map_flags (op->map, &m, dx, dy, &dx, &dy); 1012 mflags = get_map_flags (op->map, &m, dx, dy, &dx, &dy);
1013
1014 // when creating a bomb below ourself it should always work, even
1015 // when movement is blocked (somehow we got here, somehow we are here,
1016 // so we should also be able to make a bomb here). (originally added
1017 // to fix create bomb traps in doors, which cast with dir=0).
1018 if (dir)
1019 {
1007 if ((mflags & P_OUT_OF_MAP) || (GET_MAP_MOVE_BLOCK (m, dx, dy) & MOVE_WALK)) 1020 if ((mflags & P_OUT_OF_MAP) || (GET_MAP_MOVE_BLOCK (m, dx, dy) & MOVE_WALK))
1008 { 1021 {
1009 new_draw_info (NDI_UNIQUE, 0, op, "There is something in the way."); 1022 new_draw_info (NDI_UNIQUE, 0, op, "There is something in the way.");
1010 return 0; 1023 return 0;
1024 }
1011 } 1025 }
1012 1026
1013 tmp = arch_to_object (spell->other_arch); 1027 tmp = arch_to_object (spell->other_arch);
1014 1028
1015 /* level dependencies for bomb */ 1029 /* level dependencies for bomb */
1115 effect = arch_to_object (spell->other_arch); 1129 effect = arch_to_object (spell->other_arch);
1116 else 1130 else
1117 return 0; 1131 return 0;
1118 1132
1119 /* tailor the effect by priest level and worshipped God */ 1133 /* tailor the effect by priest level and worshipped God */
1120 effect->level = caster_level (caster, spell); 1134 effect->level = casting_level (caster, spell);
1121 effect->attacktype = spell->attacktype; 1135 effect->attacktype = spell->attacktype;
1122 if (effect->attacktype & (AT_HOLYWORD | AT_GODPOWER)) 1136 if (effect->attacktype & (AT_HOLYWORD | AT_GODPOWER))
1123 { 1137 {
1124 if (tailor_god_spell (effect, op)) 1138 if (tailor_god_spell (effect, op))
1125 new_draw_info_format (NDI_UNIQUE, 0, op, "%s answers your call!", determine_god (op)); 1139 new_draw_info_format (NDI_UNIQUE, 0, op, "%s answers your call!", determine_god (op));
1180 1194
1181/* op is a missile that needs to be moved */ 1195/* op is a missile that needs to be moved */
1182void 1196void
1183move_missile (object *op) 1197move_missile (object *op)
1184{ 1198{
1185 int i, mflags;
1186 object *owner;
1187 sint16 new_x, new_y;
1188 maptile *m;
1189
1190 if (op->range-- <= 0) 1199 if (op->range-- <= 0)
1191 { 1200 {
1201 op->drop_and_destroy ();
1202 return;
1203 }
1204
1205 mapxy pos (op);
1206 pos.move (op->direction);
1207
1208 if (!pos.normalise ())
1209 {
1192 op->destroy (); 1210 op->destroy ();
1193 return; 1211 return;
1194 } 1212 }
1195 1213
1196 owner = op->owner; 1214 mapspace &ms = pos.ms ();
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 {
1203 op->destroy ();
1204 return;
1205 }
1206#endif
1207 1215
1208 new_x = op->x + DIRX (op); 1216 if (ms.flags () & P_IS_ALIVE || ms.blocks (op))
1209 new_y = op->y + DIRY (op);
1210
1211 mflags = get_map_flags (op->map, &m, new_x, new_y, &new_x, &new_y);
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 { 1217 {
1215 hit_map (op, op->direction, AT_MAGIC, 1); 1218 hit_map (op, op->direction, AT_MAGIC, 1);
1216 /* Basically, missile only hits one thing then goes away. 1219 /* Basically, missile only hits one thing then goes away.
1217 * we need to remove it if someone hasn't already done so. 1220 * we need to remove it if someone hasn't already done so.
1218 */ 1221 */
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 (); 1222 op->destroy ();
1230 return; 1223 return;
1231 } 1224 }
1232 1225
1226 if (!op->direction)
1227 {
1228 op->destroy ();
1229 return;
1230 }
1231
1233 i = spell_find_dir (m, new_x, new_y, op->owner); 1232 int i = spell_find_dir (pos.m, pos.x, pos.y, op->owner);
1234 if (i > 0 && i != op->direction) 1233 if (i > 0 && i != op->direction)
1235 { 1234 {
1236 op->direction = i; 1235 op->direction = i;
1237 SET_ANIMATION (op, op->direction); 1236 SET_ANIMATION (op, op->direction);
1238 } 1237 }
1239 1238
1240 m->insert (op, new_x, new_y, op); 1239 pos.insert (op, op);
1241} 1240}
1242 1241
1243/**************************************************************************** 1242/****************************************************************************
1244 * Destruction 1243 * Destruction
1245 ****************************************************************************/ 1244 ****************************************************************************/
1259 1258
1260 object *tmp = get_archetype (FORCE_NAME); 1259 object *tmp = get_archetype (FORCE_NAME);
1261 tmp->speed = 0.01; 1260 tmp->speed = 0.01;
1262 tmp->stats.food = time; 1261 tmp->stats.food = time;
1263 SET_FLAG (tmp, FLAG_IS_USED_UP); 1262 SET_FLAG (tmp, FLAG_IS_USED_UP);
1264 tmp->glow_radius = radius;
1265 if (tmp->glow_radius > MAX_LIGHT_RADII)
1266 tmp->glow_radius = MAX_LIGHT_RADII; 1263 tmp->glow_radius = min (MAX_LIGHT_RADIUS, radius);
1267
1268 tmp = insert_ob_in_ob (tmp, op); 1264 tmp = insert_ob_in_ob (tmp, op);
1269 1265
1270 if (tmp->glow_radius > op->glow_radius) 1266 if (tmp->glow_radius > op->glow_radius)
1271 op->glow_radius = tmp->glow_radius; 1267 op->glow_radius = tmp->glow_radius;
1272 1268
1302 else 1298 else
1303 op->skill = NULL; 1299 op->skill = NULL;
1304 1300
1305 op->change_skill (find_skill_by_name (op, op->skill)); 1301 op->change_skill (find_skill_by_name (op, op->skill));
1306 1302
1307 for (i = -range; i < range; i++) 1303 for (i = -range; i <= range; i++)
1308 { 1304 {
1309 for (j = -range; j < range; j++) 1305 for (j = -range; j <= range; j++)
1310 { 1306 {
1311 m = op->map; 1307 m = op->map;
1312 sx = op->x + i; 1308 sx = op->x + i;
1313 sy = op->y + j; 1309 sy = op->y + j;
1314 1310
1331 (!friendly && (QUERY_FLAG (tmp, FLAG_FRIENDLY) || tmp->type == PLAYER))) 1327 (!friendly && (QUERY_FLAG (tmp, FLAG_FRIENDLY) || tmp->type == PLAYER)))
1332 { 1328 {
1333 if (spell_ob->subtype == SP_DESTRUCTION) 1329 if (spell_ob->subtype == SP_DESTRUCTION)
1334 { 1330 {
1335 hit_player (tmp, dam, op, spell_ob->attacktype, 0); 1331 hit_player (tmp, dam, op, spell_ob->attacktype, 0);
1332
1336 if (spell_ob->other_arch) 1333 if (spell_ob->other_arch)
1337 m->insert (arch_to_object (spell_ob->other_arch), sx, sy, op); 1334 m->insert (arch_to_object (spell_ob->other_arch), sx, sy, op);
1338 } 1335 }
1339 else if (spell_ob->subtype == SP_FAERY_FIRE && tmp->resist[ATNR_MAGIC] != 100) 1336 else if (spell_ob->subtype == SP_FAERY_FIRE && tmp->resist[ATNR_MAGIC] != 100)
1340 { 1337 {
1468 1465
1469 /* We precompute some values here so that we don't have to keep 1466 /* We precompute some values here so that we don't have to keep
1470 * doing it over and over again. 1467 * doing it over and over again.
1471 */ 1468 */
1472 god = find_god (determine_god (op)); 1469 god = find_god (determine_god (op));
1473 level = caster_level (caster, spell); 1470 level = casting_level (caster, spell);
1474 range = spell->range + SP_level_range_adjust (caster, spell); 1471 range = spell->range + SP_level_range_adjust (caster, spell);
1475 1472
1476 /* On the bright side, no monster should ever have a race of GOD_... 1473 /* 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 1474 * so even if the player doesn't worship a god, if race=GOD_.., it
1478 * won't ever match anything. 1475 * won't ever match anything.
1501 if (!(mflags & P_IS_ALIVE)) 1498 if (!(mflags & P_IS_ALIVE))
1502 continue; 1499 continue;
1503 1500
1504 // players can only affect spaces that they can actually see 1501 // players can only affect spaces that they can actually see
1505 if (caster && caster->contr 1502 if (caster && caster->contr
1506 && caster->contr->visibility_at (m, nx, ny) < 70) 1503 && caster->contr->darkness_at (m, nx, ny) == LOS_BLOCKED)
1507 continue; 1504 continue;
1508 1505
1509 for (tmp = GET_MAP_TOP (m, nx, ny); tmp; tmp = tmp->below) 1506 for (tmp = GET_MAP_TOP (m, nx, ny); tmp; tmp = tmp->below)
1510 if (QUERY_FLAG (tmp, FLAG_MONSTER)) 1507 if (QUERY_FLAG (tmp, FLAG_MONSTER))
1511 break; 1508 break;
1621 } /* for y */ 1618 } /* for y */
1622 1619
1623 return 1; 1620 return 1;
1624} 1621}
1625 1622
1626
1627/* Move_ball_spell: This handles ball type spells that just sort of wander 1623/* Move_ball_spell: This handles ball type spells that just sort of wander
1628 * about. was called move_ball_lightning, but since more than the ball 1624 * about. was called move_ball_lightning, but since more than the ball
1629 * lightning spell used it, that seemed misnamed. 1625 * lightning spell used it, that seemed misnamed.
1630 * op is the spell effect. 1626 * op is the spell effect.
1631 * note that duration is handled by process_object() in time.c 1627 * note that duration is handled by process_object() in time.c
1632 */ 1628 */
1633
1634void 1629void
1635move_ball_spell (object *op) 1630move_ball_spell (object *op)
1636{ 1631{
1637 int i, j, dam_save, dir, mflags; 1632 int i, j, dam_save, dir, mflags;
1638 sint16 nx, ny, hx, hy; 1633 sint16 nx, ny, hx, hy;
1657 for (i = 1; i < 9; i++) 1652 for (i = 1; i < 9; i++)
1658 { 1653 {
1659 /* i bit 0: alters sign of offset 1654 /* i bit 0: alters sign of offset
1660 * other bits (i / 2): absolute value of offset 1655 * other bits (i / 2): absolute value of offset
1661 */ 1656 */
1662
1663 int offset = ((i ^ j) & 1) ? (i / 2) : -(i / 2); 1657 int offset = ((i ^ j) & 1) ? (i / 2) : -(i / 2);
1664 int tmpdir = absdir (op->direction + offset); 1658 int tmpdir = absdir (op->direction + offset);
1665 1659
1666 nx = op->x + freearr_x[tmpdir]; 1660 nx = op->x + freearr_x[tmpdir];
1667 ny = op->y + freearr_y[tmpdir]; 1661 ny = op->y + freearr_y[tmpdir];
1669 { 1663 {
1670 dir = tmpdir; 1664 dir = tmpdir;
1671 break; 1665 break;
1672 } 1666 }
1673 } 1667 }
1668
1674 if (dir == 0) 1669 if (dir == 0)
1675 { 1670 {
1676 nx = op->x; 1671 nx = op->x;
1677 ny = op->y; 1672 ny = op->y;
1678 m = op->map; 1673 m = op->map;
1704 1699
1705 if ((mflags & P_IS_ALIVE) && (!owner || owner->x != hx || owner->y != hy || !on_same_map (owner, op))) 1700 if ((mflags & P_IS_ALIVE) && (!owner || owner->x != hx || owner->y != hy || !on_same_map (owner, op)))
1706 { 1701 {
1707 if (j) 1702 if (j)
1708 op->stats.dam = dam_save / 2; 1703 op->stats.dam = dam_save / 2;
1704
1709 hit_map (op, j, op->attacktype, 1); 1705 hit_map (op, j, op->attacktype, 1);
1710
1711 } 1706 }
1712 1707
1713 /* insert the other arch */ 1708 /* insert the other arch */
1714 if (op->other_arch && !(OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, hx, hy)))) 1709 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); 1710 m->insert (arch_to_object (op->other_arch), hx, hy, op);
1729 1724
1730 op->direction = i; 1725 op->direction = i;
1731 } 1726 }
1732} 1727}
1733 1728
1734
1735/* move_swarm_spell: peterm 1729/* move_swarm_spell: peterm
1736 * This is an implementation of the swarm spell. It was written for 1730 * This is an implementation of the swarm spell. It was written for
1737 * meteor swarm, but it could be used for any swarm. A swarm spell 1731 * meteor swarm, but it could be used for any swarm. A swarm spell
1738 * is a special type of object that casts swarms of other types 1732 * is a special type of object that casts swarms of other types
1739 * of spells. Which spell it casts is flexible. It fires the spells 1733 * of spells. Which spell it casts is flexible. It fires the spells
1740 * from a set of squares surrounding the caster, in a given direction. 1734 * from a set of squares surrounding the caster, in a given direction.
1741 */ 1735 */
1742
1743void 1736void
1744move_swarm_spell (object *op) 1737move_swarm_spell (object *op)
1745{ 1738{
1746#if 0 1739#if 0
1747 static int cardinal_adjust[9] = { -3, -2, -1, 0, 0, 0, 1, 2, 3 }; 1740 static int cardinal_adjust[9] = { -3, -2, -1, 0, 0, 0, 1, 2, 3 };
1748 static int diagonal_adjust[10] = { -3, -2, -2, -1, 0, 0, 1, 2, 2, 3 }; 1741 static int diagonal_adjust[10] = { -3, -2, -2, -1, 0, 0, 1, 2, 2, 3 };
1749 sint16 target_x, target_y, origin_x, origin_y; 1742 sint16 target_x, target_y, origin_x, origin_y;
1750 int adjustdir; 1743 int adjustdir;
1751 maptile *m; 1744 maptile *m;
1752#endif 1745#endif
1753 int basedir;
1754 object *owner; 1746 object *owner = op->env;
1755 1747
1756 owner = op->owner; 1748 if (!owner) // MUST not happen, remove when true TODO
1757 if (op->duration == 0 || owner == NULL)
1758 { 1749 {
1750 LOG (llevError, "swarm spell found outside inventory: %s\n", op->debug_desc ());
1759 op->destroy (); 1751 op->destroy ();
1760 return; 1752 return;
1761 } 1753 }
1762 1754
1755 if (!op->duration || !owner->is_on_map ())
1756 {
1757 op->drop_and_destroy ();
1758 return;
1759 }
1760
1763 op->duration--; 1761 op->duration--;
1764 1762
1765 basedir = op->direction; 1763 int basedir = op->direction;
1766 if (basedir == 0) 1764 if (!basedir)
1767 { 1765 {
1768 /* spray in all directions! 8) */ 1766 /* spray in all directions! 8) */
1769 basedir = rndm (1, 8); 1767 op->facing = (op->facing + op->state) & 7;
1768 basedir = op->facing + 1;
1770 } 1769 }
1771 1770
1772#if 0 1771#if 0
1773 // this is bogus: it causes wrong places to be checked below 1772 // this is bogus: it causes wrong places to be checked below
1774 // (a wall 2 cells away will block the effect...) and 1773 // (a wall 2 cells away will block the effect...) and
1835 { 1834 {
1836 /* Bullet spells have a bunch more customization that needs to be done */ 1835 /* Bullet spells have a bunch more customization that needs to be done */
1837 if (op->spell->subtype == SP_BULLET) 1836 if (op->spell->subtype == SP_BULLET)
1838 fire_bullet (owner, op, basedir, op->spell); 1837 fire_bullet (owner, op, basedir, op->spell);
1839 else if (op->spell->subtype == SP_MAGIC_MISSILE) 1838 else if (op->spell->subtype == SP_MAGIC_MISSILE)
1840 fire_arch_from_position (owner, op, op->x, op->y, basedir, op->spell); 1839 fire_arch_from_position (owner, op, owner->x, owner->y, basedir, op->spell);
1841 } 1840 }
1842} 1841}
1843
1844
1845
1846 1842
1847/* fire_swarm: 1843/* fire_swarm:
1848 * The following routine creates a swarm of objects. It actually 1844 * The following routine creates a swarm of objects. It actually
1849 * sets up a specific swarm object, which then fires off all 1845 * sets up a specific swarm object, which then fires off all
1850 * the parts of the swarm. 1846 * the parts of the swarm.
1853 * caster: the caster (owner, wand, rod, scroll) 1849 * caster: the caster (owner, wand, rod, scroll)
1854 * dir: the direction everything will be fired in 1850 * dir: the direction everything will be fired in
1855 * spell - the spell that is this spell. 1851 * spell - the spell that is this spell.
1856 * n: the number to be fired. 1852 * n: the number to be fired.
1857 */ 1853 */
1858
1859int 1854int
1860fire_swarm (object *op, object *caster, object *spell, int dir) 1855fire_swarm (object *op, object *caster, object *spell, int dir)
1861{ 1856{
1862 object *tmp;
1863 int i;
1864
1865 if (!spell->other_arch) 1857 if (!spell->other_arch)
1866 return 0; 1858 return 0;
1867 1859
1868 tmp = get_archetype (SWARM_SPELL); 1860 object *tmp = archetype::get (SWARM_SPELL);
1869 tmp->set_owner (op); /* needed so that if swarm elements kill, caster gets xp. */ 1861
1870 set_spell_skill (op, caster, spell, tmp); 1862 set_spell_skill (op, caster, spell, tmp);
1871
1872 tmp->level = caster_level (caster, spell); /*needed later, to get level dep. right. */ 1863 tmp->level = casting_level (caster, spell); /* needed later, to get level dep. right. */
1873 tmp->spell = arch_to_object (spell->other_arch); 1864 tmp->spell = spell->other_arch->instance ();
1874
1875 tmp->attacktype = tmp->spell->attacktype; 1865 tmp->attacktype = tmp->spell->attacktype;
1876 1866
1877 if (tmp->attacktype & AT_HOLYWORD || tmp->attacktype & AT_GODPOWER) 1867 if (tmp->attacktype & AT_HOLYWORD || tmp->attacktype & AT_GODPOWER)
1878 if (!tailor_god_spell (tmp, op)) 1868 if (!tailor_god_spell (tmp, op))
1879 return 1; 1869 return 1;
1880 1870
1881 tmp->duration = SP_level_duration_adjust (caster, spell); 1871 tmp->duration = SP_level_duration_adjust (caster, spell);
1882 for (i = 0; i < spell->duration; i++) 1872 for (int i = 0; i < spell->duration; i++)
1883 tmp->duration += die_roll (1, 3, op, PREFER_HIGH); 1873 tmp->duration += die_roll (1, 3, op, PREFER_HIGH);
1884 1874
1875 tmp->invisible = 1;
1876 tmp->flag [FLAG_NO_DROP] = 1; // make sure it stays in inv, or else
1885 tmp->direction = dir; 1877 tmp->direction = dir;
1886 tmp->invisible = 1; 1878 tmp->facing = rndm (1, 8); // initial firing direction
1879 tmp->state = rndm (4) * 2 + 1; // direction increment
1887 1880
1888 tmp->insert_at (op, op); 1881 op->insert (tmp);
1882
1889 return 1; 1883 return 1;
1890} 1884}
1891
1892 1885
1893/* See the spells documentation file for why this is its own 1886/* See the spells documentation file for why this is its own
1894 * function. 1887 * function.
1895 */ 1888 */
1896int 1889int
1901 int dam, mflags; 1894 int dam, mflags;
1902 maptile *m; 1895 maptile *m;
1903 1896
1904 dam = spell->stats.dam + SP_level_dam_adjust (caster, spell); 1897 dam = spell->stats.dam + SP_level_dam_adjust (caster, spell);
1905 1898
1906 if (!dir) 1899 if (dir)
1907 {
1908 new_draw_info (NDI_UNIQUE, 0, op, "In what direction?");
1909 return 0;
1910 } 1900 {
1911
1912 x = op->x + freearr_x[dir]; 1901 x = op->x + freearr_x[dir];
1913 y = op->y + freearr_y[dir]; 1902 y = op->y + freearr_y[dir];
1914 m = op->map; 1903 m = op->map;
1915 1904
1916 mflags = get_map_flags (m, &m, x, y, &x, &y); 1905 mflags = get_map_flags (m, &m, x, y, &x, &y);
1917 1906
1918 if (mflags & P_OUT_OF_MAP) 1907 if (mflags & P_OUT_OF_MAP)
1919 { 1908 {
1920 new_draw_info (NDI_UNIQUE, 0, op, "Nothing is there."); 1909 new_draw_info (NDI_UNIQUE, 0, op, "Nothing is there.");
1921 return 0; 1910 return 0;
1922 } 1911 }
1923 1912
1924 if (mflags & P_IS_ALIVE && spell->attacktype) 1913 if (mflags & P_IS_ALIVE && spell->attacktype)
1925 { 1914 {
1926 for (target = GET_MAP_OB (m, x, y); target; target = target->above) 1915 for (target = GET_MAP_OB (m, x, y); target; target = target->above)
1927 if (QUERY_FLAG (target, FLAG_MONSTER)) 1916 if (QUERY_FLAG (target, FLAG_MONSTER))
1928 { 1917 {
1929 /* oky doky. got a target monster. Lets make a blinding attack */ 1918 /* oky doky. got a target monster. Lets make a blinding attack */
1930 if (target->head) 1919 if (target->head)
1931 target = target->head; 1920 target = target->head;
1921
1932 (void) hit_player (target, dam, op, spell->attacktype, 1); 1922 hit_player (target, dam, op, spell->attacktype, 1);
1933 return 1; /* one success only! */ 1923 return 1; /* one success only! */
1924 }
1934 } 1925 }
1935 }
1936 1926
1937 /* no live target, perhaps a wall is in the way? */ 1927 /* no live target, perhaps a wall is in the way? */
1938 if (OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, x, y))) 1928 if (OB_TYPE_MOVE_BLOCK (op, GET_MAP_MOVE_BLOCK (m, x, y)))
1939 { 1929 {
1940 new_draw_info (NDI_UNIQUE, 0, op, "Something is in the way."); 1930 new_draw_info (NDI_UNIQUE, 0, op, "Something is in the way.");
1941 return 0; 1931 return 0;
1932 }
1942 } 1933 }
1943 1934
1944 /* ok, looks groovy to just insert a new light on the map */ 1935 /* ok, looks groovy to just insert a new light on the map */
1945 tmp = arch_to_object (spell->other_arch); 1936 tmp = arch_to_object (spell->other_arch);
1946 if (!tmp) 1937 if (!tmp)
1947 { 1938 {
1948 LOG (llevError, "Error: spell arch for cast_light() missing.\n"); 1939 LOG (llevError, "Error: spell arch for cast_light() missing.\n");
1949 return 0; 1940 return 0;
1950 } 1941 }
1942
1951 tmp->stats.food = spell->duration + SP_level_duration_adjust (caster, spell); 1943 tmp->stats.food = spell->duration + SP_level_duration_adjust (caster, spell);
1944
1952 if (tmp->glow_radius) 1945 if (tmp->glow_radius)
1953 {
1954 tmp->glow_radius = spell->range + SP_level_range_adjust (caster, spell); 1946 tmp->glow_radius = min (MAX_LIGHT_RADIUS, spell->range + SP_level_range_adjust (caster, spell));
1955 if (tmp->glow_radius > MAX_LIGHT_RADII)
1956 tmp->glow_radius = MAX_LIGHT_RADII;
1957 }
1958 1947
1948 if (dir)
1959 m->insert (tmp, x, y, op); 1949 m->insert (tmp, x, y, op);
1950 else
1951 caster->outer_env ()->insert (tmp);
1952
1960 return 1; 1953 return 1;
1961} 1954}
1962 1955
1963/* cast_cause_disease: this spell looks along <dir> from the 1956/* cast_cause_disease: this spell looks along <dir> from the
1964 * player and infects someone. 1957 * player and infects someone.
2017 object *disease = arch_to_object (spell->other_arch); 2010 object *disease = arch_to_object (spell->other_arch);
2018 2011
2019 disease->set_owner (op); 2012 disease->set_owner (op);
2020 set_spell_skill (op, caster, spell, disease); 2013 set_spell_skill (op, caster, spell, disease);
2021 disease->stats.exp = 0; 2014 disease->stats.exp = 0;
2022 disease->level = caster_level (caster, spell); 2015 disease->level = casting_level (caster, spell);
2023 2016
2024 /* do level adjustments */ 2017 /* do level adjustments */
2025 if (disease->stats.wc) 2018 if (disease->stats.wc)
2026 disease->stats.wc += dur_mod / 2; 2019 disease->stats.wc += dur_mod / 2;
2027 2020

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines