Crossfire Server, Trunk
spell_effect.cpp
Go to the documentation of this file.
1 /*
2  CrossFire, A Multiplayer game for X-windows
3 
4  Copyright (C) 2007 Mark Wedel & Crossfire Development Team
5  Copyright (C) 1992 Frank Tore Johansen
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21  The authors can be reached via e-mail at crossfire-devel@real-time.com
22 */
23 
28 #include <global.h>
29 #include <ob_methods.h>
30 #include <ob_types.h>
31 #include <sounds.h>
32 #include <sproto.h>
33 
34 static method_ret spell_effect_type_move_on(object *trap, object *victim, object *originator);
36 
37 static void move_bolt(object *op);
38 static object *move_bullet(object *op);
39 static void explosion(object *op);
40 static void move_cone(object *op);
41 static void animate_bomb(object *op);
42 static void move_missile(object *op);
43 static void execute_word_of_recall(object *op);
44 static void move_ball_spell(object *op);
45 static void move_swarm_spell(object *op);
46 static void move_aura(object *aura);
47 
48 static void forklightning(object *op, object *tmp);
49 static void check_spell_knockback(object *op);
50 
57 }
58 
66 static method_ret spell_effect_type_move_on(object *trap, object *victim, object *originator) {
67  if (common_pre_ob_move_on(trap, victim, originator) == METHOD_ERROR)
68  return METHOD_OK;
69 
70  switch (trap->subtype) {
71  case SP_CONE:
73  && trap->speed
74  && trap->attacktype)
75  hit_player(victim, trap->stats.dam, trap, trap->attacktype, 0);
76  break;
77 
78  case SP_MAGIC_MISSILE:
80  tag_t spell_tag = trap->count;
81 
82  hit_player(victim, trap->stats.dam, trap, trap->attacktype, 1);
83  if (!object_was_destroyed(trap, spell_tag)) {
84  object_remove(trap);
86  }
87  }
88  break;
89 
90  case SP_MOVING_BALL:
92  hit_player(victim, trap->stats.dam, trap, trap->attacktype, 1);
93  else if (victim->material || victim->materialname)
94  save_throw_object(victim, trap->attacktype, trap);
95  break;
96  }
97  common_post_ob_move_on(trap, victim, originator);
98  return METHOD_OK;
99 }
100 
107  switch (op->subtype) {
108  case SP_BOLT:
109  move_bolt(op);
110  break;
111 
112  case SP_BULLET:
113  move_bullet(op);
114  break;
115 
116  case SP_EXPLOSION:
117  explosion(op);
118  break;
119 
120  case SP_CONE:
121  move_cone(op);
122  break;
123 
124  case SP_BOMB:
125  animate_bomb(op);
126  break;
127 
128  case SP_MAGIC_MISSILE:
129  move_missile(op);
130  break;
131 
132  case SP_WORD_OF_RECALL:
134  break;
135 
136  case SP_MOVING_BALL:
138  break;
139 
140  case SP_SWARM:
142  break;
143 
144  case SP_AURA:
145  move_aura(op);
146  break;
147  }
148  return METHOD_OK;
149 }
150 
156 static void move_bolt(object *op) {
157  object *tmp;
158  int mflags;
159  int16_t x, y;
160  mapstruct *m;
161 
162  if (--(op->duration) < 0) {
163  object_remove(op);
165  return;
166  }
167  hit_map(op, 0, op->attacktype, 1);
168 
170 
171  if (!op->direction)
172  return;
173 
174  if (--op->range < 0) {
175  op->range = 0;
176  } else {
177  x = op->x+DIRX(op);
178  y = op->y+DIRY(op);
179  m = op->map;
180  mflags = get_map_flags(m, &m, x, y, &x, &y);
181 
182  if (mflags&P_OUT_OF_MAP)
183  return;
184 
185  /* We are about to run into something - we may bounce */
186  /* Calling reflwall is pretty costly, as it has to look at all the objects
187  * on the space. So only call reflwall if we think the data it returns
188  * will be useful.
189  */
191  || ((mflags&P_IS_ALIVE) && reflwall(m, x, y, op))) {
193  return;
194 
195  /* Since walls don't run diagonal, if the bolt is in
196  * one of 4 main directions, it just reflects back in the
197  * opposite direction. However, if the bolt is travelling
198  * on the diagonal, it is trickier - eg, a bolt travelling
199  * northwest bounces different if it hits a north/south
200  * wall (bounces to northeast) vs an east/west (bounces
201  * to the southwest.
202  */
203  if (op->direction&1) {
204  op->direction = absdir(op->direction+4);
205  } else {
206  int left, right;
207  int mflags;
208 
209  /* Need to check for P_OUT_OF_MAP: if the bolt is tavelling
210  * over a corner in a tiled map, it is possible that
211  * op->direction is within an adjacent map but either
212  * op->direction-1 or op->direction+1 does not exist.
213  */
214  mflags = get_map_flags(op->map, &m, op->x+freearr_x[absdir(op->direction-1)], op->y+freearr_y[absdir(op->direction-1)], &x, &y);
215 
216  left = (mflags&P_OUT_OF_MAP) ? 0 : OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, x, y));
217 
218  mflags = get_map_flags(op->map, &m, op->x+freearr_x[absdir(op->direction+1)], op->y+freearr_y[absdir(op->direction+1)], &x, &y);
219  right = (mflags&P_OUT_OF_MAP) ? 0 : OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, x, y));
220 
221  if (left == right)
222  op->direction = absdir(op->direction+4);
223  else if (left)
224  op->direction = absdir(op->direction+2);
225  else if (right)
226  op->direction = absdir(op->direction-2);
227  }
228  object_update_turn_face(op); /* A bolt *must *be IS_TURNABLE */
229  return;
230  } else { /* Create a copy of this object and put it ahead */
231  tmp = object_new();
232  object_copy(op, tmp);
233  tmp->speed_left = -0.1;
234  tmp = object_insert_in_map_at(tmp, op->map, op, 0, op->x+DIRX(op), op->y+DIRY(op));
235  /* To make up for the decrease at the top of the function */
236  tmp->duration++;
237 
238  /* New forking code. Possibly create forks of this object
239  * going off in other directions.
240  */
241 
242  if (rndm(0, 99) < tmp->stats.Dex) { /* stats.Dex % of forking */
243  forklightning(op, tmp);
244  }
245  /* In this way, the object left behind sticks on the space, but
246  * doesn't create any bolts that continue to move onward.
247  */
248  op->range = 0;
249  } /* copy object and move it along */
250  } /* if move bolt along */
251 }
252 
260 static object *move_bullet(object *op) {
261  int16_t new_x, new_y;
262  int mflags;
263  mapstruct *m;
264 
265  /* Reached the end of its life - remove it */
266  if (--op->range <= 0) {
267  if (op->other_arch) {
269  } else {
270  object_remove(op);
272  }
273  return NULL;
274  }
275 
276  new_x = op->x+DIRX(op);
277  new_y = op->y+DIRY(op);
278  m = op->map;
279  mflags = get_map_flags(m, &m, new_x, new_y, &new_x, &new_y);
280 
281  if (mflags&P_OUT_OF_MAP) {
282  object_remove(op);
284  return NULL;
285  }
286 
287  if (!op->direction || OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, new_x, new_y))) {
288  if (op->other_arch) {
290  } else {
291  object_remove(op);
293  }
294  return NULL;
295  }
296 
297  object_remove(op);
298  if ((op = object_insert_in_map_at(op, m, op, 0, new_x, new_y)) == NULL)
299  return NULL;
300 
301  if (reflwall(op->map, op->x, op->y, op)) {
302  op->direction = absdir(op->direction+4);
304  return op;
305  }
306 
307  check_bullet(op); // Handles collisions with living things.
308  if (QUERY_FLAG(op, FLAG_FREED)) {
309  // check_bullet() might have deleted it, if it hit something.
310  return NULL;
311  }
312  return op;
313 }
314 
320 static void explosion(object *op) {
321  object *tmp;
322  mapstruct *m = op->map;
323  int i;
324 
325  if (--(op->duration) < 0) {
326  object_remove(op);
328  return;
329  }
330  hit_map(op, 0, op->attacktype, 0);
332 
333  if (op->range > 0) {
334  for (i = 1; i < 9; i++) {
335  int16_t dx, dy;
336  int16_t Dx, Dy;
337  dx = op->x+freearr_x[i];
338  dy = op->y+freearr_y[i];
339  /* ok_to_put_more already does things like checks for walls,
340  * out of map, etc.
341  */
342  if (ok_to_put_more(op->map, dx, dy, op, op->attacktype)) {
343  tmp = object_new();
344  object_copy(op, tmp);
345  tmp->state = 0;
346  tmp->speed_left = -0.21;
347  tmp->range--;
348  tmp->value = 0;
349  Dx=dx-op->x;
350  Dy=dy-op->y;
351  if (Dx==-1 && Dy==-1){
352  tmp->direction=8;
353  }
354  if (Dx==0 && Dy==-1){
355  tmp->direction=1;
356  }
357  if (Dx==1 && Dy==-1){
358  tmp->direction=2;
359  }
360  if (Dx==1 && Dy==0){
361  tmp->direction=3;
362  }
363  if (Dx==1 && Dy==1){
364  tmp->direction=4;
365  }
366  if (Dx==0 && Dy==1){
367  tmp->direction=5;
368  }
369  if (Dx==-1 && Dy==-1){
370  tmp->direction=6;
371  }
372  if (Dx==-1 && Dy==0){
373  tmp->direction=7;
374  }
375 
376  object_insert_in_map_at(tmp, m, op, 0, dx, dy);
377 
378  }
379  }
380  /* Reset range so we don't try to propogate anymore.
381  * Call object_merge_spell() to see if we can merge with another
382  * spell on the space.
383  */
384  op->range = 0;
385  object_merge_spell(op, op->x, op->y);
386  }
387 }
388 
393 static void move_cone(object *op) {
394  int i;
395  tag_t tag;
396 
397  /* if no map then hit_map will crash so just ignore object */
398  if (!op->map) {
399  LOG(llevError, "Tried to move_cone object %s without a map.\n", op->name ? op->name : "unknown");
400  op->speed = 0;
402  return;
403  }
404 
405  /* lava saves it's life, but not yours :) */
406  if (QUERY_FLAG(op, FLAG_LIFESAVE)) {
407  hit_map(op, 0, op->attacktype, 0);
408  return;
409  }
410 
411  tag = op->count;
412  hit_map(op, 0, op->attacktype, 0);
413 
414  /* Check to see if we should push anything.
415  * Spell objects with weight push whatever they encounter to some
416  * degree.
417  */
419 
421  return;
422 
423  if ((op->duration--) < 0) {
424  object_remove(op);
426  return;
427  }
428 
429  /* Object has hit maximum range, so don't have it move
430  * any further. When the duration above expires,
431  * then the object will get removed.
432  */
433  if (--op->range < 0) {
434  op->range = 0; /* just so it doesn't wrap */
435  return;
436  }
437 
438  for (i = -1; i < 2; i++) {
439  int16_t x = op->x+freearr_x[absdir(op->stats.sp+i)];
440  int16_t y = op->y+freearr_y[absdir(op->stats.sp+i)];
441 
442  if (ok_to_put_more(op->map, x, y, op, op->attacktype)) {
443  object *tmp = object_new();
444 
445  object_copy(op, tmp);
446  tmp->duration = op->duration+1;
447 
448  /* Use for spell tracking - see ok_to_put_more() */
449  tmp->stats.maxhp = op->stats.maxhp;
450  object_insert_in_map_at(tmp, op->map, op, 0, x, y);
451  if (tmp->other_arch)
452  cone_drop(tmp);
453  }
454  }
455 }
456 
461 static void animate_bomb(object *op) {
462  int i;
463  object *env, *tmp;
464  archetype *at;
465 
466  if (op->state != NUM_ANIMATIONS(op)-1)
467  return;
468 
470 
471  if (op->env) {
472  if (env->map == NULL)
473  return;
474 
475  object_remove(op);
476  if ((op = object_insert_in_map_at(op, env->map, op, 0, env->x, env->y)) == NULL)
477  return;
478  }
479 
480  /* This copies a lot of the code from the fire bullet,
481  * but using the cast_bullet isn't really feasible,
482  * so just set up the appropriate values.
483  */
484  at = find_archetype(SPLINT);
485  if (at) {
486  for (i = 1; i < 9; i++) {
487  if (out_of_map(op->map, op->x+freearr_x[i], op->y+freearr_x[i]))
488  continue;
489  tmp = arch_to_object(at);
490  tmp->direction = i;
491  tmp->range = op->range;
492  tmp->stats.dam = op->stats.dam;
493  tmp->duration = op->duration;
494  tmp->attacktype = op->attacktype;
496  if (op->skill && op->skill != tmp->skill) {
497  if (tmp->skill)
498  free_string(tmp->skill);
499  tmp->skill = add_refcount(op->skill);
500  }
502  object_insert_in_map_at(tmp, op->map, op, 0, op->x+freearr_x[i], op->y+freearr_x[i]);
503  ob_process(tmp);
504  }
505  }
506 
508 }
509 
516 static void move_missile(object *op) {
517  // Handles actual movement, collision detection, making it explode
518  // if it has an other_arch and hit something or timed out, etc.
519  // This might have deleted the missile, in which case we bail early.
520  if ((op = move_bullet(op)) == NULL) return;
521 
522  // Still here? Home in on something. Doing this after move_bullet
523  // means that (a) the missile visibly points to where it's about
524  // to move and (b) sufficiently fast enemies can dodge it to some
525  // extent, which looks cool.
526  int dir = spell_find_dir(op->map, op->x, op->y, object_get_owner(op));
527  if (dir > 0 && dir != op->direction) {
528  op->direction = adjust_dir(op->direction, dir);
530  }
531 }
532 
537 static void execute_word_of_recall(object *op) {
538  object *wor = op;
539 
540  while (op != NULL && op->type != PLAYER)
541  op = op->env;
542 
543  if (op != NULL) {
544  // Drop any unpaid items that would be carried.
545  // This prevents abuse of balms of return home in shops.
546  remove_unpaid_objects(op->inv, op, 0);
547 
548  enter_exit(op, wor);
549  }
550  object_remove(wor);
552 }
553 
559 static void move_ball_spell(object *op) {
560  int i, j, dam_save, dir, mflags;
561  int16_t nx, ny, hx, hy;
562  object *owner;
563  mapstruct *m;
564 
565  owner = object_get_owner(op);
566 
567  /* the following logic makes sure that the ball doesn't move into a wall,
568  * and makes sure that it will move along a wall to try and get at it's
569  * victim. The block immediately below more or less chooses a random
570  * offset to move the ball, eg, keep it mostly on course, with some
571  * deviations.
572  */
573 
574  dir = 0;
575  j = rndm(0, 1);
576  for (i = 1; i <= 9; i++) {
577  /* i bit 0: alters sign of offset
578  * other bits (i/2): absolute value of offset
579  */
580 
581  int offset = ((i^j)&1) ? (i/2) : -(i/2);
582  int tmpdir = absdir(op->direction+offset);
583 
584  nx = op->x+freearr_x[tmpdir];
585  ny = op->y+freearr_y[tmpdir];
586  if (!(get_map_flags(op->map, &m, nx, ny, &nx, &ny)&P_OUT_OF_MAP)
587  && !(OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, nx, ny)))) {
588  dir = tmpdir;
589  break;
590  }
591  }
592  if (dir == 0) {
593  nx = op->x;
594  ny = op->y;
595  m = op->map;
596  }
597 
598  object_remove(op);
599  object_insert_in_map_at(op, m, op, 0, nx, ny);
600 
601  dam_save = op->stats.dam; /* save the original dam: we do halfdam on
602  surrounding squares */
603 
604  /* loop over current square and neighbors to hit.
605  * if this has an other_arch field, we insert that in
606  * the surround spaces.
607  */
608  for (j = 0; j < 9; j++) {
609  object *new_ob;
610 
611  hx = nx+freearr_x[j];
612  hy = ny+freearr_y[j];
613 
614  m = op->map;
615  mflags = get_map_flags(m, &m, hx, hy, &hx, &hy);
616 
617  if (mflags&P_OUT_OF_MAP)
618  continue;
619 
620  /* first, don't ever, ever hit the owner. Don't hit out
621  * of the map either.
622  */
623 
624  if ((mflags&P_IS_ALIVE) && (!owner || owner->x != hx || owner->y != hy || !on_same_map(owner, op))) {
625  if (j)
626  op->stats.dam = dam_save/2;
627  hit_map(op, j, op->attacktype, 1);
628  }
629 
630  /* insert the other arch */
631  if (op->other_arch && !(OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, hx, hy)))) {
632  new_ob = arch_to_object(op->other_arch);
633  object_insert_in_map_at(new_ob, m, op, 0, hx, hy);
634  }
635  }
636 
637  /* restore to the center location and damage*/
638  op->stats.dam = dam_save;
639 
640  i = spell_find_dir(op->map, op->x, op->y, object_get_owner(op));
641  if (i >= 0) { /* we have a preferred direction! */
642  op->direction = adjust_dir(op->direction, i);
643  if (rndm(0, 3) != 0)
644  op->direction = adjust_dir(op->direction, i);
645  if (rndm(0, 3) == 0)
646  op->direction = adjust_dir(op->direction, i);
647  }
648 }
649 
650 /*
651  * This is an implementation of the swarm spell. It was written for meteor
652  * swarm, but it could be used for any swarm. A swarm spell is a special type
653  * of object that casts swarms of other types of spells. Which spell it casts
654  * is flexible. It fires the spells from a set of squares surrounding the
655  * caster, in a given direction.
656  * @param op The spell effect.
657  */
658 static void move_swarm_spell(object *op) {
659  static int cardinal_adjust[9] = { -3, -2, -1, 0, 0, 0, 1, 2, 3 };
660  static int diagonal_adjust[10] = { -3, -2, -2, -1, 0, 0, 1, 2, 2, 3 };
661  int16_t target_x, target_y, origin_x, origin_y;
662  int basedir, adjustdir;
663  mapstruct *m;
664  object *owner;
665 
666  owner = object_get_owner(op);
667  if (op->duration == 0 || owner == NULL || owner->x != op->x || owner->y != op->y) {
668  object_remove(op);
670  return;
671  }
672  op->duration--;
673 
674  basedir = op->direction;
675  if (basedir == 0) {
676  /* spray in all directions! 8) */
677  basedir = get_random_dir();
678  }
679 
680  /* new offset calculation to make swarm element distribution
681  * more uniform
682  */
683  if (op->duration) {
684  if (basedir&1) {
685  adjustdir = cardinal_adjust[rndm(0, 8)];
686  } else {
687  adjustdir = diagonal_adjust[rndm(0, 9)];
688  }
689  } else {
690  adjustdir = 0; /* fire the last one from forward. */
691  }
692 
693  target_x = op->x+freearr_x[absdir(basedir+adjustdir)];
694  target_y = op->y+freearr_y[absdir(basedir+adjustdir)];
695 
696  /* back up one space so we can hit point-blank targets, but this
697  * necessitates extra out_of_map check below
698  */
699  origin_x = target_x-freearr_x[basedir];
700  origin_y = target_y-freearr_y[basedir];
701 
702 
703  /* spell pointer is set up for the spell this casts. Since this
704  * should just be a pointer to the spell in some inventory,
705  * it is unlikely to disappear by the time we need it. However,
706  * do some sanity checking anyways.
707  */
708 
709  if (op->spell && op->spell->type == SPELL && !(get_map_flags(op->map, &m, target_x, target_y, &target_x, &target_y)&P_OUT_OF_MAP)) {
710  /* Bullet spells have a bunch more customization that needs to be done */
711  if (op->spell->subtype == SP_BULLET)
712  fire_arch_from_position(owner, op, origin_x+freearr_x[basedir], origin_y+freearr_y[basedir], basedir, op->spell);
713  else if (op->spell->subtype == SP_MAGIC_MISSILE)
714  fire_arch_from_position(owner, op, origin_x, origin_y, basedir, op->spell);
715  }
716 }
717 
728 static void move_aura(object *aura) {
729  int i, j, mflags;
730  object *caster;
731  mapstruct *m;
732  uint8_t aura_animation_state = 0;
733  sstring whole_aura_animation = NULL;
734  char aura_animation_name[200];
735  if (aura->other_arch && aura->other_arch->clone.type != SPELL) {
736  whole_aura_animation = object_get_value(&aura->other_arch->clone, "whole_aura_animation");
737  if (whole_aura_animation) {
738  snprintf(aura_animation_name, sizeof(aura_animation_name), "%s_0_0", whole_aura_animation);
739  Animations *anim = try_find_animation(aura_animation_name);
740  if (anim) {
741  aura_animation_state = aura->duration % (anim->num_animations / anim->facings);
742  } else {
743  whole_aura_animation = NULL;
744  }
745  }
746  }
747 
748  /* auras belong in inventories */
749  caster = aura->env;
750 
751  /* no matter what we've gotta remove the aura...
752  * we'll put it back if its time isn't up.
753  */
754  object_remove(aura);
755 
756  /* exit if we're out of gas */
757  if (aura->duration-- < 0) {
759  return;
760  }
761 
762  /* auras only exist in inventories */
763  if (caster == NULL || caster->map == NULL) {
765  return;
766  }
767 
768  for (i = -aura->range; i <= aura->range; i++) {
769  for (j = -aura->range; j <= aura->range; ++j) {
770  int16_t nx, ny;
771 
772  // Caster should be the starting location for the aura, so use
773  // it as the base positioning instead of the aura.
774  // This allows us to be less hacky when handling the long-range aura.
775  nx = caster->x+i;
776  ny = caster->y+j;
777  mflags = get_map_flags(caster->map, &m, nx, ny, &nx, &ny);
778 
779  /* Consider the movement type of the person with the aura as
780  * movement type of the aura. Eg, if the player is flying, the aura
781  * is flying also, if player is walking, it is on the ground, etc.
782  */
783  if (!(mflags&P_OUT_OF_MAP) && !(OB_TYPE_MOVE_BLOCK(caster, GET_MAP_MOVE_BLOCK(m, nx, ny)))) {
784  // If the aura has no attacktype, don't try to hit the map with it.
785  // Chances are, it is casting it's own spell instead.
786  if (aura->attacktype != 0 && (i != 0 || j != 0)) {
787  // Instead of using freearr in hit_map, be move the aura around,
788  // and then call hit_map with direction 0. This allows us to have range > 3.
789 
790  /* we need to jump out of the inventory for a bit
791  * in order to hit the map conveniently.
792  */
793  if (!QUERY_FLAG(aura, FLAG_REMOVED))
794  object_remove(aura);
795  object_insert_in_map_at(aura, m, aura, 0, nx, ny);
796  hit_map(aura, 0, aura->attacktype, 0);
797  object_remove(aura);
798  }
799 
800  if (aura->other_arch) {
801  object *new_ob;
802 
803  new_ob = arch_to_object(aura->other_arch);
804  // If the aura contains a spell, we attempt to cast the spell on every tile we affect.
805  if (new_ob->type != SPELL) {
806  new_ob = object_insert_in_map_at(new_ob, m, aura, 0, nx, ny);
807  if (new_ob && whole_aura_animation) {
808  snprintf(aura_animation_name, sizeof(aura_animation_name), "%s_%d_%d", whole_aura_animation, i + aura->range, j + aura->range);
809  Animations *anim = try_find_animation(aura_animation_name);
810  if (anim) {
811  SET_FLAG(new_ob, FLAG_ANIMATE);
812  new_ob->animation = anim;
813  new_ob->state = aura_animation_state;
814  animate_object(new_ob, 0);
815  }
816  }
817  }
818  else if (i != 0 || j != 0) {
819  // Find a living creature that is on the same side as the caster.
820  FOR_MAP_PREPARE(m, nx, ny, tmp) {
821  // If the entity is living and aligned with the caster, then cast the spell at them.
822  // Allow auras to be cast by enemies, too. In that case, they only affect their allies.
823  if (QUERY_FLAG(tmp, FLAG_ALIVE) &&
825  (QUERY_FLAG(caster, FLAG_FRIENDLY) || IS_PLAYER(caster)))){
826  cast_spell(tmp, aura, 0, new_ob, NULL);
827  }
828  } FOR_MAP_FINISH();
830  }
831  }
832  }
833  }
834  }
835 
836  /* put the aura back in the player's inventory */
837  if (!QUERY_FLAG(aura, FLAG_REMOVED))
838  object_remove(aura);
839  object_insert_in_ob(aura, caster);
840  check_spell_expiry(aura);
841 }
842 
848 static void forklightning(object *op, object *tmp) {
849  int new_dir = 1; /* direction or -1 for left, +1 for right 0 if no new bolt */
850  int t_dir; /* stores temporary dir calculation */
851  mapstruct *m;
852  int16_t sx, sy;
853  object *new_bolt;
854 
855  /* pick a fork direction. tmp->stats.Con is the left bias
856  * i.e., the chance in 100 of forking LEFT
857  * Should start out at 50, down to 25 for one already going left
858  * down to 0 for one going 90 degrees left off original path
859  */
860 
861  if (rndm(0, 99) < tmp->stats.Con) /* fork left */
862  new_dir = -1;
863 
864  /* check the new dir for a wall and in the map*/
865  t_dir = absdir(tmp->direction+new_dir);
866 
867  if (get_map_flags(tmp->map, &m, tmp->x+freearr_x[t_dir], tmp->y+freearr_y[t_dir], &sx, &sy)&P_OUT_OF_MAP)
868  return;
869 
871  return;
872 
873  /* OK, we made a fork */
874  new_bolt = object_new();
875 
876  object_copy(tmp, new_bolt);
877 
878  /* reduce chances of subsequent forking */
879  new_bolt->stats.Dex -= 10;
880  tmp->stats.Dex -= 10; /* less forks from main bolt too */
881  new_bolt->stats.Con += 25*new_dir; /* adjust the left bias */
882  new_bolt->speed_left = -0.1;
883  new_bolt->direction = t_dir;
884  new_bolt->duration++;
885  new_bolt->stats.dam /= 2; /* reduce daughter bolt damage */
886  new_bolt->stats.dam++;
887  tmp->stats.dam /= 2; /* reduce father bolt damage */
888  tmp->stats.dam++;
889  new_bolt = object_insert_in_map_at(new_bolt, m, op, 0, sx, sy);
890  object_update_turn_face(new_bolt);
891 }
892 
899 static void check_spell_knockback(object *op) {
900  object *tmp, *tmp2; /* object on the map */
901  int weight_move;
902  int frictionmod = 2; /*poor man's physics - multipy targets weight by this amount */
903 
904  /* if cone object has no weight drop out */
905  if (!op->weight) {
906  return;
907  }
908 
909  weight_move = op->weight+(op->weight*op->level)/3;
910  /*LOG(llevDebug, "DEBUG: arch weighs %d and masses %d (%s,level %d)\n", op->weight, weight_move, op->name, op->level);*/
911 
912  for (tmp = GET_MAP_OB(op->map, op->x, op->y); tmp != NULL; tmp = tmp->above) {
913  int num_sections = 1;
914 
915  /* don't move DM */
916  if (QUERY_FLAG(tmp, FLAG_WIZ))
917  return;
918 
919  /* don't move parts of objects */
920  if (tmp->head)
921  continue;
922 
923  /* don't move floors or immobile objects */
925  continue;
926 
927  /* count the object's sections */
928  for (tmp2 = tmp; tmp2 != NULL; tmp2 = tmp2->more)
929  num_sections++;
930 
931  /* I'm not sure if it makes sense to divide by num_sections - bigger
932  * objects should be harder to move, and we are moving the entire
933  * object, not just the head, so the total weight should be relevant.
934  */
935 
936  /* surface area? -tm */
937 
938  if (tmp->move_type&MOVE_FLYING)
939  frictionmod = 1; /* flying objects loose the friction modifier */
940  if (rndm(0, weight_move-1) > ((tmp->weight/num_sections)*frictionmod)) { /* move it. */
941  /* move_object is really for monsters, but looking at
942  * the move_object function, it appears that it should
943  * also be safe for objects.
944  * This does return if successful or not, but
945  * I don't see us doing anything useful with that information
946  * right now.
947  */
948 // LOG(llevDebug, "trying move\n");
949  if (op->direction){
950  move_object(tmp,absdir(op->direction));
951  }
952 
953  else {
954  (move_object(tmp, absdir(op->stats.sp)));
955 
956  }
957  }
958  else{
959 // LOG(llevDebug, "did not try move, don't know why\n");
960  }
961  }
962 }
object_was_destroyed
#define object_was_destroyed(op, old_tag)
Definition: object.h:70
GET_MAP_OB
#define GET_MAP_OB(M, X, Y)
Definition: map.h:170
PLAYER
@ PLAYER
Definition: object.h:112
object_get_owner
object * object_get_owner(object *op)
Definition: object.cpp:804
SP_MAGIC_MISSILE
#define SP_MAGIC_MISSILE
Definition: spells.h:85
global.h
FREE_OBJ_NO_DESTROY_CALLBACK
#define FREE_OBJ_NO_DESTROY_CALLBACK
Definition: object.h:545
SP_BOLT
#define SP_BOLT
Definition: spells.h:78
object_get_env_recursive
object * object_get_env_recursive(object *op)
Definition: object.cpp:590
object_update_turn_face
void object_update_turn_face(object *op)
Definition: object.cpp:1332
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Definition: define.h:730
spell_effect_type_move_on
static method_ret spell_effect_type_move_on(object *trap, object *victim, object *originator)
Definition: spell_effect.cpp:66
llevError
@ llevError
Definition: logger.h:11
SP_BOMB
#define SP_BOMB
Definition: spells.h:82
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:58
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
diamondslots.x
x
Definition: diamondslots.py:15
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
get_random_dir
int get_random_dir(void)
Definition: utils.cpp:400
check_spell_knockback
static void check_spell_knockback(object *op)
Definition: spell_effect.cpp:899
cast_spell
int cast_spell(object *op, object *caster, int dir, object *spell_ob, char *stringarg)
Definition: spell_util.cpp:1424
absdir
int absdir(int d)
Definition: object.cpp:3710
move_cone
static void move_cone(object *op)
Definition: spell_effect.cpp:393
object::range
int8_t range
Definition: object.h:417
object::speed
float speed
Definition: object.h:337
METHOD_OK
#define METHOD_OK
Definition: ob_methods.h:15
living::Dex
int8_t Dex
Definition: living.h:36
object::x
int16_t x
Definition: object.h:335
check_bullet
void check_bullet(object *op)
Definition: spell_attack.cpp:217
object::speed_left
float speed_left
Definition: object.h:338
object::map
struct mapstruct * map
Definition: object.h:305
register_move_on
void register_move_on(int ob_type, move_on_func method)
Definition: ob_types.cpp:89
explode_bullet
void explode_bullet(object *op)
Definition: spell_attack.cpp:121
SP_CONE
#define SP_CONE
Definition: spells.h:81
object::direction
int8_t direction
Definition: object.h:344
object::count
tag_t count
Definition: object.h:307
object_copy
void object_copy(const object *src_ob, object *dest_ob)
Definition: object.cpp:1192
DIRX
#define DIRX(xyz)
Definition: define.h:463
Ice.tmp
int tmp
Definition: Ice.py:207
hit_map
int hit_map(object *op, int dir, uint32_t type, int full_hit)
Definition: attack.cpp:355
rndm
int rndm(int min, int max)
Definition: utils.cpp:162
register_process
void register_process(int ob_type, process_func method)
Definition: ob_types.cpp:71
fire_arch_from_position
int fire_arch_from_position(object *op, object *caster, int16_t x, int16_t y, int dir, object *spell)
Definition: spell_util.cpp:629
object_get_value
const char * object_get_value(const object *op, const char *const key)
Definition: object.cpp:4342
P_IS_ALIVE
#define P_IS_ALIVE
Definition: map.h:235
ok_to_put_more
int ok_to_put_more(mapstruct *m, int16_t x, int16_t y, object *op, uint32_t immune_stop)
Definition: spell_util.cpp:530
object_merge_spell
void object_merge_spell(object *op, int16_t x, int16_t y)
Definition: object.cpp:2129
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
Definition: object.cpp:2853
FLAG_NO_PICK
#define FLAG_NO_PICK
Definition: define.h:239
FLAG_ALIVE
#define FLAG_ALIVE
Definition: define.h:230
move_bullet
static object * move_bullet(object *op)
Definition: spell_effect.cpp:260
object::y
int16_t y
Definition: object.h:335
m
static event_registration m
Definition: citylife.cpp:425
SPLINT
#define SPLINT
Definition: spells.h:165
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.cpp:1560
SP_BULLET
#define SP_BULLET
Definition: spells.h:79
spell_find_dir
int spell_find_dir(mapstruct *m, int x, int y, object *exclude)
Definition: spell_util.cpp:887
object::subtype
uint8_t subtype
Definition: object.h:349
add_refcount
sstring add_refcount(sstring str)
Definition: shstr.cpp:210
adjust_dir
int adjust_dir(int dir, int destination_dir)
Definition: utils.cpp:426
freearr_y
short freearr_y[SIZEOFFREE]
Definition: object.cpp:305
remove_unpaid_objects
void remove_unpaid_objects(object *op, object *env, int free_items)
Definition: player.cpp:3207
archetype::clone
object clone
Definition: object.h:487
move_ball_spell
static void move_ball_spell(object *op)
Definition: spell_effect.cpp:559
sword_of_souls.victim
victim
Definition: sword_of_souls.py:12
cone_drop
void cone_drop(object *op)
Definition: spell_attack.cpp:265
common_pre_ob_move_on
method_ret common_pre_ob_move_on(object *trap, object *victim, object *originator)
Definition: common_apply.cpp:35
spell_effect_type_process
static method_ret spell_effect_type_process(object *op)
Definition: spell_effect.cpp:106
FLAG_FREED
#define FLAG_FREED
Definition: define.h:233
out_of_map
int out_of_map(mapstruct *m, int x, int y)
Definition: map.cpp:2289
MOVE_FLYING
#define MOVE_FLYING
Definition: define.h:395
object_update_speed
void object_update_speed(object *op)
Definition: object.cpp:1349
move_swarm_spell
static void move_swarm_spell(object *op)
Definition: spell_effect.cpp:658
object::type
uint8_t type
Definition: object.h:348
living::dam
int16_t dam
Definition: living.h:46
CFweardisguise.tag
tag
Definition: CFweardisguise.py:25
object_free
void object_free(object *ob, int flags)
Definition: object.cpp:1592
GET_MAP_MOVE_BLOCK
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Definition: map.h:190
FLAG_UNAGGRESSIVE
#define FLAG_UNAGGRESSIVE
Definition: define.h:272
move_bolt
static void move_bolt(object *op)
Definition: spell_effect.cpp:156
tag_t
uint32_t tag_t
Definition: object.h:14
archetype
Definition: object.h:483
sproto.h
animate.anim
string anim
Definition: animate.py:20
object::animation
const Animations * animation
Definition: object.h:428
execute_word_of_recall
static void execute_word_of_recall(object *op)
Definition: spell_effect.cpp:537
object_insert_in_map_at
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.cpp:2100
object::other_arch
struct archetype * other_arch
Definition: object.h:425
forklightning
static void forklightning(object *op, object *tmp)
Definition: spell_effect.cpp:848
P_OUT_OF_MAP
#define P_OUT_OF_MAP
Definition: map.h:247
env
static std::shared_ptr< inja::Environment > env
Definition: mapper.cpp:2168
object_new
object * object_new(void)
Definition: object.cpp:1273
free_string
void free_string(sstring str)
Definition: shstr.cpp:280
try_find_animation
Animations * try_find_animation(const char *name)
Definition: assets.cpp:278
move_object
int move_object(object *op, int dir)
Definition: move.cpp:39
IS_PLAYER
static bool IS_PLAYER(object *op)
Definition: object.h:609
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:723
method_ret
char method_ret
Definition: ob_methods.h:14
ob_types.h
explosion
static void explosion(object *op)
Definition: spell_effect.cpp:320
sounds.h
FLAG_REMOVED
#define FLAG_REMOVED
Definition: define.h:232
FLAG_WIZ
#define FLAG_WIZ
Definition: define.h:231
animate_bomb
static void animate_bomb(object *op)
Definition: spell_effect.cpp:461
FLAG_FRIENDLY
#define FLAG_FRIENDLY
Definition: define.h:246
ob_process
method_ret ob_process(object *op)
Definition: ob_methods.cpp:67
get_map_flags
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
Definition: map.cpp:300
SP_MOVING_BALL
#define SP_MOVING_BALL
Definition: spells.h:109
mapstruct
Definition: map.h:313
enter_exit
void enter_exit(object *op, object *exit_ob)
Definition: server.cpp:738
object::env
object * env
Definition: object.h:301
sstring
const typedef char * sstring
Definition: sstring.h:2
give.op
op
Definition: give.py:33
Animations
Definition: face.h:25
animate_object
void animate_object(object *op, int dir)
Definition: anim.cpp:44
find_archetype
archetype * find_archetype(const char *name)
Definition: assets.cpp:266
FLAG_REFLECTING
#define FLAG_REFLECTING
Definition: define.h:262
move_aura
static void move_aura(object *aura)
Definition: spell_effect.cpp:728
SPELL_EFFECT
@ SPELL_EFFECT
Definition: object.h:220
hit_player
int hit_player(object *op, int dam, object *hitter, uint32_t type, int full_hit)
Definition: attack.cpp:1903
diamondslots.y
y
Definition: diamondslots.py:16
on_same_map
int on_same_map(const object *op1, const object *op2)
Definition: map.cpp:2628
NUM_ANIMATIONS
#define NUM_ANIMATIONS(ob)
Definition: global.h:171
object::duration
int16_t duration
Definition: object.h:415
check_spell_expiry
void check_spell_expiry(object *spell)
Definition: spell_util.cpp:2006
arch_to_object
object * arch_to_object(archetype *at)
Definition: arch.cpp:229
FLAG_ANIMATE
#define FLAG_ANIMATE
Definition: define.h:242
object_remove
void object_remove(object *op)
Definition: object.cpp:1833
reflwall
int reflwall(mapstruct *m, int x, int y, object *sp_op)
Definition: spell_util.cpp:470
OB_TYPE_MOVE_BLOCK
#define OB_TYPE_MOVE_BLOCK(ob1, type)
Definition: define.h:432
METHOD_ERROR
#define METHOD_ERROR
Definition: ob_methods.h:17
FREE_OBJ_FREE_INVENTORY
#define FREE_OBJ_FREE_INVENTORY
Definition: object.h:544
object::state
uint8_t state
Definition: object.h:359
object_copy_owner
void object_copy_owner(object *op, object *clone)
Definition: object.cpp:893
ob_methods.h
object::stats
living stats
Definition: object.h:378
object::more
object * more
Definition: object.h:303
freearr_x
short freearr_x[SIZEOFFREE]
Definition: object.cpp:299
SPELL
@ SPELL
Definition: object.h:219
save_throw_object
void save_throw_object(object *op, uint32_t type, object *originator)
Definition: attack.cpp:202
SP_SWARM
#define SP_SWARM
Definition: spells.h:110
object::attacktype
uint32_t attacktype
Definition: object.h:352
common_post_ob_move_on
void common_post_ob_move_on(object *trap, object *victim, object *originator)
Definition: common_apply.cpp:67
init_type_spell_effect
void init_type_spell_effect(void)
Definition: spell_effect.cpp:54
SP_EXPLOSION
#define SP_EXPLOSION
Definition: spells.h:80
FLAG_LIFESAVE
#define FLAG_LIFESAVE
Definition: define.h:305
DIRY
#define DIRY(xyz)
Definition: define.h:464
SP_WORD_OF_RECALL
#define SP_WORD_OF_RECALL
Definition: spells.h:92
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Definition: define.h:302
living::Con
int8_t Con
Definition: living.h:36
move_missile
static void move_missile(object *op)
Definition: spell_effect.cpp:516
SP_AURA
#define SP_AURA
Definition: spells.h:120