Crossfire Server, Trunk  R21466
spell_effect.c
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(ob_methods *context, object *trap, object *victim, object *originator);
35 static method_ret spell_effect_type_process(ob_methods *context, object *op);
36 
37 static void move_bolt(object *op);
38 static void 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 
67 static method_ret spell_effect_type_move_on(ob_methods *context, object *trap, object *victim, object *originator) {
68  if (common_pre_ob_move_on(trap, victim, originator) == METHOD_ERROR)
69  return METHOD_OK;
70 
71  switch (trap->subtype) {
72  case SP_CONE:
73  if (QUERY_FLAG(victim, FLAG_ALIVE)
74  && trap->speed
75  && trap->attacktype)
76  hit_player(victim, trap->stats.dam, trap, trap->attacktype, 0);
77  break;
78 
79  case SP_MAGIC_MISSILE:
80  if (QUERY_FLAG(victim, FLAG_ALIVE)) {
81  tag_t spell_tag = trap->count;
82 
83  hit_player(victim, trap->stats.dam, trap, trap->attacktype, 1);
84  if (!object_was_destroyed(trap, spell_tag)) {
85  object_remove(trap);
87  }
88  }
89  break;
90 
91  case SP_MOVING_BALL:
92  if (QUERY_FLAG(victim, FLAG_ALIVE))
93  hit_player(victim, trap->stats.dam, trap, trap->attacktype, 1);
94  else if (victim->material || victim->materialname)
95  save_throw_object(victim, trap->attacktype, trap);
96  break;
97  }
98  common_post_ob_move_on(trap, victim, originator);
99  return METHOD_OK;
100 }
101 
108 static method_ret spell_effect_type_process(ob_methods *context, object *op) {
109  switch (op->subtype) {
110  case SP_BOLT:
111  move_bolt(op);
112  break;
113 
114  case SP_BULLET:
115  move_bullet(op);
116  break;
117 
118  case SP_EXPLOSION:
119  explosion(op);
120  break;
121 
122  case SP_CONE:
123  move_cone(op);
124  break;
125 
126  case SP_BOMB:
127  animate_bomb(op);
128  break;
129 
130  case SP_MAGIC_MISSILE:
131  move_missile(op);
132  break;
133 
134  case SP_WORD_OF_RECALL:
136  break;
137 
138  case SP_MOVING_BALL:
139  move_ball_spell(op);
140  break;
141 
142  case SP_SWARM:
143  move_swarm_spell(op);
144  break;
145 
146  case SP_AURA:
147  move_aura(op);
148  break;
149  }
150  return METHOD_OK;
151 }
152 
158 static void move_bolt(object *op) {
159  object *tmp;
160  int mflags;
161  int16_t x, y;
162  mapstruct *m;
163 
164  if (--(op->duration) < 0) {
165  object_remove(op);
167  return;
168  }
169  hit_map(op, 0, op->attacktype, 1);
170 
172 
173  if (!op->direction)
174  return;
175 
176  if (--op->range < 0) {
177  op->range = 0;
178  } else {
179  x = op->x+DIRX(op);
180  y = op->y+DIRY(op);
181  m = op->map;
182  mflags = get_map_flags(m, &m, x, y, &x, &y);
183 
184  if (mflags&P_OUT_OF_MAP)
185  return;
186 
187  /* We are about to run into something - we may bounce */
188  /* Calling reflwall is pretty costly, as it has to look at all the objects
189  * on the space. So only call reflwall if we think the data it returns
190  * will be useful.
191  */
192  if (OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, x, y))
193  || ((mflags&P_IS_ALIVE) && reflwall(m, x, y, op))) {
194  if (!QUERY_FLAG(op, FLAG_REFLECTING))
195  return;
196 
197  /* Since walls don't run diagonal, if the bolt is in
198  * one of 4 main directions, it just reflects back in the
199  * opposite direction. However, if the bolt is travelling
200  * on the diagonal, it is trickier - eg, a bolt travelling
201  * northwest bounces different if it hits a north/south
202  * wall (bounces to northeast) vs an east/west (bounces
203  * to the southwest.
204  */
205  if (op->direction&1) {
206  op->direction = absdir(op->direction+4);
207  } else {
208  int left, right;
209  int mflags;
210 
211  /* Need to check for P_OUT_OF_MAP: if the bolt is tavelling
212  * over a corner in a tiled map, it is possible that
213  * op->direction is within an adjacent map but either
214  * op->direction-1 or op->direction+1 does not exist.
215  */
216  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);
217 
218  left = (mflags&P_OUT_OF_MAP) ? 0 : OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, x, y));
219 
220  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);
221  right = (mflags&P_OUT_OF_MAP) ? 0 : OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, x, y));
222 
223  if (left == right)
224  op->direction = absdir(op->direction+4);
225  else if (left)
226  op->direction = absdir(op->direction+2);
227  else if (right)
228  op->direction = absdir(op->direction-2);
229  }
230  object_update_turn_face(op); /* A bolt *must *be IS_TURNABLE */
231  return;
232  } else { /* Create a copy of this object and put it ahead */
233  tmp = object_new();
234  object_copy(op, tmp);
235  tmp->speed_left = -0.1;
236  tmp = object_insert_in_map_at(tmp, op->map, op, 0, op->x+DIRX(op), op->y+DIRY(op));
237  /* To make up for the decrease at the top of the function */
238  tmp->duration++;
239 
240  /* New forking code. Possibly create forks of this object
241  * going off in other directions.
242  */
243 
244  if (rndm(0, 99) < tmp->stats.Dex) { /* stats.Dex % of forking */
245  forklightning(op, tmp);
246  }
247  /* In this way, the object left behind sticks on the space, but
248  * doesn't create any bolts that continue to move onward.
249  */
250  op->range = 0;
251  } /* copy object and move it along */
252  } /* if move bolt along */
253 }
254 
261 static void move_bullet(object *op) {
262  int16_t new_x, new_y;
263  int mflags;
264  mapstruct *m;
265 
266  /* Reached the end of its life - remove it */
267  if (--op->range <= 0) {
268  if (op->other_arch) {
269  explode_bullet(op);
270  } else {
271  object_remove(op);
273  }
274  return;
275  }
276 
277  new_x = op->x+DIRX(op);
278  new_y = op->y+DIRY(op);
279  m = op->map;
280  mflags = get_map_flags(m, &m, new_x, new_y, &new_x, &new_y);
281 
282  if (mflags&P_OUT_OF_MAP) {
283  object_remove(op);
285  return;
286  }
287 
288  if (!op->direction || OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, new_x, new_y))) {
289  if (op->other_arch) {
290  explode_bullet(op);
291  } else {
292  object_remove(op);
294  }
295  return;
296  }
297 
298  object_remove(op);
299  if ((op = object_insert_in_map_at(op, m, op, 0, new_x, new_y)) == NULL)
300  return;
301 
302  if (reflwall(op->map, op->x, op->y, op)) {
303  op->direction = absdir(op->direction+4);
305  } else {
306  check_bullet(op);
307  }
308 }
309 
315 static void explosion(object *op) {
316  object *tmp;
317  mapstruct *m = op->map;
318  int i;
319 
320  if (--(op->duration) < 0) {
321  object_remove(op);
323  return;
324  }
325  hit_map(op, 0, op->attacktype, 0);
327 
328  if (op->range > 0) {
329  for (i = 1; i < 9; i++) {
330  int16_t dx, dy;
331  int16_t Dx, Dy;
332  dx = op->x+freearr_x[i];
333  dy = op->y+freearr_y[i];
334  /* ok_to_put_more already does things like checks for walls,
335  * out of map, etc.
336  */
337  if (ok_to_put_more(op->map, dx, dy, op, op->attacktype)) {
338  tmp = object_new();
339  object_copy(op, tmp);
340  tmp->state = 0;
341  tmp->speed_left = -0.21;
342  tmp->range--;
343  tmp->value = 0;
344  Dx=dx-op->x;
345  Dy=dy-op->y;
346  if (Dx==-1 && Dy==-1){
347  tmp->direction=8;
348  }
349  if (Dx==0 && Dy==-1){
350  tmp->direction=1;
351  }
352  if (Dx==1 && Dy==-1){
353  tmp->direction=2;
354  }
355  if (Dx==1 && Dy==0){
356  tmp->direction=3;
357  }
358  if (Dx==1 && Dy==1){
359  tmp->direction=4;
360  }
361  if (Dx==0 && Dy==1){
362  tmp->direction=5;
363  }
364  if (Dx==-1 && Dy==-1){
365  tmp->direction=6;
366  }
367  if (Dx==-1 && Dy==0){
368  tmp->direction=7;
369  }
370 
371  object_insert_in_map_at(tmp, m, op, 0, dx, dy);
372 
373  }
374  }
375  /* Reset range so we don't try to propogate anymore.
376  * Call object_merge_spell() to see if we can merge with another
377  * spell on the space.
378  */
379  op->range = 0;
380  object_merge_spell(op, op->x, op->y);
381  }
382 }
383 
388 static void move_cone(object *op) {
389  int i;
390  tag_t tag;
391 
392  /* if no map then hit_map will crash so just ignore object */
393  if (!op->map) {
394  LOG(llevError, "Tried to move_cone object %s without a map.\n", op->name ? op->name : "unknown");
395  op->speed = 0;
397  return;
398  }
399 
400  /* lava saves it's life, but not yours :) */
401  if (QUERY_FLAG(op, FLAG_LIFESAVE)) {
402  hit_map(op, 0, op->attacktype, 0);
403  return;
404  }
405 
406  tag = op->count;
407  hit_map(op, 0, op->attacktype, 0);
408 
409  /* Check to see if we should push anything.
410  * Spell objects with weight push whatever they encounter to some
411  * degree.
412  */
414 
415  if (object_was_destroyed(op, tag))
416  return;
417 
418  if ((op->duration--) < 0) {
419  object_remove(op);
421  return;
422  }
423 
424  /* Object has hit maximum range, so don't have it move
425  * any further. When the duration above expires,
426  * then the object will get removed.
427  */
428  if (--op->range < 0) {
429  op->range = 0; /* just so it doesn't wrap */
430  return;
431  }
432 
433  for (i = -1; i < 2; i++) {
434  int16_t x = op->x+freearr_x[absdir(op->stats.sp+i)];
435  int16_t y = op->y+freearr_y[absdir(op->stats.sp+i)];
436 
437  if (ok_to_put_more(op->map, x, y, op, op->attacktype)) {
438  object *tmp = object_new();
439 
440  object_copy(op, tmp);
441  tmp->duration = op->duration+1;
442 
443  /* Use for spell tracking - see ok_to_put_more() */
444  tmp->stats.maxhp = op->stats.maxhp;
445  object_insert_in_map_at(tmp, op->map, op, 0, x, y);
446  if (tmp->other_arch)
447  cone_drop(tmp);
448  }
449  }
450 }
451 
456 static void animate_bomb(object *op) {
457  int i;
458  object *env, *tmp;
459  archetype *at;
460 
461  if (op->state != NUM_ANIMATIONS(op)-1)
462  return;
463 
464  env = object_get_env_recursive(op);
465 
466  if (op->env) {
467  if (env->map == NULL)
468  return;
469 
470  object_remove(op);
471  if ((op = object_insert_in_map_at(op, env->map, op, 0, env->x, env->y)) == NULL)
472  return;
473  }
474 
475  /* This copies a lot of the code from the fire bullet,
476  * but using the cast_bullet isn't really feasible,
477  * so just set up the appropriate values.
478  */
479  at = find_archetype(SPLINT);
480  if (at) {
481  for (i = 1; i < 9; i++) {
482  if (out_of_map(op->map, op->x+freearr_x[i], op->y+freearr_x[i]))
483  continue;
484  tmp = arch_to_object(at);
485  tmp->direction = i;
486  tmp->range = op->range;
487  tmp->stats.dam = op->stats.dam;
488  tmp->duration = op->duration;
489  tmp->attacktype = op->attacktype;
490  object_copy_owner(tmp, op);
491  if (op->skill && op->skill != tmp->skill) {
492  if (tmp->skill)
493  free_string(tmp->skill);
494  tmp->skill = add_refcount(op->skill);
495  }
497  object_insert_in_map_at(tmp, op->map, op, 0, op->x+freearr_x[i], op->y+freearr_x[i]);
498  ob_process(tmp);
499  }
500  }
501 
502  explode_bullet(op);
503 }
504 
509 static void move_missile(object *op) {
510  int i, mflags;
511  int16_t new_x, new_y;
512  mapstruct *m;
513 
514  if (op->range-- <= 0) {
515  object_remove(op);
517  return;
518  }
519 
520  /* call is required to potentially clean owner, but we don't care for the result */
521  object_get_owner(op);
522 
523  new_x = op->x+DIRX(op);
524  new_y = op->y+DIRY(op);
525 
526  mflags = get_map_flags(op->map, &m, new_x, new_y, &new_x, &new_y);
527 
528  if (!(mflags&P_OUT_OF_MAP)
529  && ((mflags&P_IS_ALIVE) || OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, new_x, new_y)))) {
530  tag_t tag = op->count;
531 
532  hit_map(op, op->direction, AT_MAGIC, 1);
533  /* Basically, missile only hits one thing then goes away.
534  * we need to remove it if someone hasn't already done so.
535  */
536  if (!object_was_destroyed(op, tag)) {
537  object_remove(op);
539  }
540  return;
541  }
542 
543  object_remove(op);
544  if (!op->direction || (mflags&P_OUT_OF_MAP)) {
546  return;
547  }
548  i = spell_find_dir(m, new_x, new_y, object_get_owner(op));
549  if (i > 0 && i != op->direction) {
550  op->direction = adjust_dir(op->direction, i);
552  }
553  object_insert_in_map_at(op, m, op, 0, new_x, new_y);
554 }
555 
560 static void execute_word_of_recall(object *op) {
561  object *wor = op;
562 
563  while (op != NULL && op->type != PLAYER)
564  op = op->env;
565 
566  if (op != NULL) {
567  enter_exit(op, wor);
568  }
569  object_remove(wor);
571 }
572 
578 static void move_ball_spell(object *op) {
579  int i, j, dam_save, dir, mflags;
580  int16_t nx, ny, hx, hy;
581  object *owner;
582  mapstruct *m;
583 
584  owner = object_get_owner(op);
585 
586  /* the following logic makes sure that the ball doesn't move into a wall,
587  * and makes sure that it will move along a wall to try and get at it's
588  * victim. The block immediately below more or less chooses a random
589  * offset to move the ball, eg, keep it mostly on course, with some
590  * deviations.
591  */
592 
593  dir = 0;
594  j = rndm(0, 1);
595  for (i = 1; i <= 9; i++) {
596  /* i bit 0: alters sign of offset
597  * other bits (i/2): absolute value of offset
598  */
599 
600  int offset = ((i^j)&1) ? (i/2) : -(i/2);
601  int tmpdir = absdir(op->direction+offset);
602 
603  nx = op->x+freearr_x[tmpdir];
604  ny = op->y+freearr_y[tmpdir];
605  if (!(get_map_flags(op->map, &m, nx, ny, &nx, &ny)&P_OUT_OF_MAP)
606  && !(OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, nx, ny)))) {
607  dir = tmpdir;
608  break;
609  }
610  }
611  if (dir == 0) {
612  nx = op->x;
613  ny = op->y;
614  m = op->map;
615  }
616 
617  object_remove(op);
618  object_insert_in_map_at(op, m, op, 0, nx, ny);
619 
620  dam_save = op->stats.dam; /* save the original dam: we do halfdam on
621  surrounding squares */
622 
623  /* loop over current square and neighbors to hit.
624  * if this has an other_arch field, we insert that in
625  * the surround spaces.
626  */
627  for (j = 0; j < 9; j++) {
628  object *new_ob;
629 
630  hx = nx+freearr_x[j];
631  hy = ny+freearr_y[j];
632 
633  m = op->map;
634  mflags = get_map_flags(m, &m, hx, hy, &hx, &hy);
635 
636  if (mflags&P_OUT_OF_MAP)
637  continue;
638 
639  /* first, don't ever, ever hit the owner. Don't hit out
640  * of the map either.
641  */
642 
643  if ((mflags&P_IS_ALIVE) && (!owner || owner->x != hx || owner->y != hy || !on_same_map(owner, op))) {
644  if (j)
645  op->stats.dam = dam_save/2;
646  hit_map(op, j, op->attacktype, 1);
647  }
648 
649  /* insert the other arch */
650  if (op->other_arch && !(OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, hx, hy)))) {
651  new_ob = arch_to_object(op->other_arch);
652  object_insert_in_map_at(new_ob, m, op, 0, hx, hy);
653  }
654  }
655 
656  /* restore to the center location and damage*/
657  op->stats.dam = dam_save;
658 
659  i = spell_find_dir(op->map, op->x, op->y, object_get_owner(op));
660  if (i >= 0) { /* we have a preferred direction! */
661  op->direction = adjust_dir(op->direction, i);
662  if (rndm(0, 3) != 0)
663  op->direction = adjust_dir(op->direction, i);
664  if (rndm(0, 3) == 0)
665  op->direction = adjust_dir(op->direction, i);
666  }
667 }
668 
669 /*
670  * This is an implementation of the swarm spell. It was written for meteor
671  * swarm, but it could be used for any swarm. A swarm spell is a special type
672  * of object that casts swarms of other types of spells. Which spell it casts
673  * is flexible. It fires the spells from a set of squares surrounding the
674  * caster, in a given direction.
675  * @param op The spell effect.
676  */
677 static void move_swarm_spell(object *op) {
678  static int cardinal_adjust[9] = { -3, -2, -1, 0, 0, 0, 1, 2, 3 };
679  static int diagonal_adjust[10] = { -3, -2, -2, -1, 0, 0, 1, 2, 2, 3 };
680  int16_t target_x, target_y, origin_x, origin_y;
681  int basedir, adjustdir;
682  mapstruct *m;
683  object *owner;
684 
685  owner = object_get_owner(op);
686  if (op->duration == 0 || owner == NULL || owner->x != op->x || owner->y != op->y) {
687  object_remove(op);
689  return;
690  }
691  op->duration--;
692 
693  basedir = op->direction;
694  if (basedir == 0) {
695  /* spray in all directions! 8) */
696  basedir = get_random_dir();
697  }
698 
699  /* new offset calculation to make swarm element distribution
700  * more uniform
701  */
702  if (op->duration) {
703  if (basedir&1) {
704  adjustdir = cardinal_adjust[rndm(0, 8)];
705  } else {
706  adjustdir = diagonal_adjust[rndm(0, 9)];
707  }
708  } else {
709  adjustdir = 0; /* fire the last one from forward. */
710  }
711 
712  target_x = op->x+freearr_x[absdir(basedir+adjustdir)];
713  target_y = op->y+freearr_y[absdir(basedir+adjustdir)];
714 
715  /* back up one space so we can hit point-blank targets, but this
716  * necessitates extra out_of_map check below
717  */
718  origin_x = target_x-freearr_x[basedir];
719  origin_y = target_y-freearr_y[basedir];
720 
721 
722  /* spell pointer is set up for the spell this casts. Since this
723  * should just be a pointer to the spell in some inventory,
724  * it is unlikely to disappear by the time we need it. However,
725  * do some sanity checking anyways.
726  */
727 
728  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)) {
729  /* Bullet spells have a bunch more customization that needs to be done */
730  if (op->spell->subtype == SP_BULLET)
731  fire_arch_from_position(owner, op, origin_x+freearr_x[basedir], origin_y+freearr_y[basedir], basedir, op->spell);
732  else if (op->spell->subtype == SP_MAGIC_MISSILE)
733  fire_arch_from_position(owner, op, origin_x, origin_y, basedir, op->spell);
734  }
735 }
736 
747 static void move_aura(object *aura) {
748  int i, mflags;
749  object *env;
750  mapstruct *m;
751 
752  /* auras belong in inventories */
753  env = aura->env;
754 
755  /* no matter what we've gotta remove the aura...
756  * we'll put it back if its time isn't up.
757  */
758  object_remove(aura);
759 
760  /* exit if we're out of gas */
761  if (aura->duration-- < 0) {
763  return;
764  }
765 
766  /* auras only exist in inventories */
767  if (env == NULL || env->map == NULL) {
769  return;
770  }
771 
772  /* we need to jump out of the inventory for a bit
773  * in order to hit the map conveniently.
774  */
775  object_insert_in_map_at(aura, env->map, aura, 0, env->x, env->y);
776 
777  for (i = 1; i < 9; i++) {
778  int16_t nx, ny;
779 
780  nx = aura->x+freearr_x[i];
781  ny = aura->y+freearr_y[i];
782  mflags = get_map_flags(env->map, &m, nx, ny, &nx, &ny);
783 
784  /* Consider the movement type of the person with the aura as
785  * movement type of the aura. Eg, if the player is flying, the aura
786  * is flying also, if player is walking, it is on the ground, etc.
787  */
788  if (!(mflags&P_OUT_OF_MAP) && !(OB_TYPE_MOVE_BLOCK(env, GET_MAP_MOVE_BLOCK(m, nx, ny)))) {
789  hit_map(aura, i, aura->attacktype, 0);
790 
791  if (aura->other_arch) {
792  object *new_ob;
793 
794  new_ob = arch_to_object(aura->other_arch);
795  object_insert_in_map_at(new_ob, m, aura, 0, nx, ny);
796  }
797  }
798  }
799 
800  /* put the aura back in the player's inventory */
801  object_remove(aura);
802  object_insert_in_ob(aura, env);
803  check_spell_expiry(aura);
804 }
805 
811 static void forklightning(object *op, object *tmp) {
812  int new_dir = 1; /* direction or -1 for left, +1 for right 0 if no new bolt */
813  int t_dir; /* stores temporary dir calculation */
814  mapstruct *m;
815  int16_t sx, sy;
816  object *new_bolt;
817 
818  /* pick a fork direction. tmp->stats.Con is the left bias
819  * i.e., the chance in 100 of forking LEFT
820  * Should start out at 50, down to 25 for one already going left
821  * down to 0 for one going 90 degrees left off original path
822  */
823 
824  if (rndm(0, 99) < tmp->stats.Con) /* fork left */
825  new_dir = -1;
826 
827  /* check the new dir for a wall and in the map*/
828  t_dir = absdir(tmp->direction+new_dir);
829 
830  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)
831  return;
832 
833  if (OB_TYPE_MOVE_BLOCK(tmp, GET_MAP_MOVE_BLOCK(m, sx, sy)))
834  return;
835 
836  /* OK, we made a fork */
837  new_bolt = object_new();
838 
839  object_copy(tmp, new_bolt);
840 
841  /* reduce chances of subsequent forking */
842  new_bolt->stats.Dex -= 10;
843  tmp->stats.Dex -= 10; /* less forks from main bolt too */
844  new_bolt->stats.Con += 25*new_dir; /* adjust the left bias */
845  new_bolt->speed_left = -0.1;
846  new_bolt->direction = t_dir;
847  new_bolt->duration++;
848  new_bolt->stats.dam /= 2; /* reduce daughter bolt damage */
849  new_bolt->stats.dam++;
850  tmp->stats.dam /= 2; /* reduce father bolt damage */
851  tmp->stats.dam++;
852  new_bolt = object_insert_in_map_at(new_bolt, m, op, 0, sx, sy);
853  object_update_turn_face(new_bolt);
854 }
855 
862 static void check_spell_knockback(object *op) {
863  object *tmp, *tmp2; /* object on the map */
864  int weight_move;
865  int frictionmod = 2; /*poor man's physics - multipy targets weight by this amount */
866 
867  /* if cone object has no weight drop out */
868  if (!op->weight) {
869  return;
870  }
871 
872  weight_move = op->weight+(op->weight*op->level)/3;
873  /*LOG(llevDebug, "DEBUG: arch weighs %d and masses %d (%s,level %d)\n", op->weight, weight_move, op->name, op->level);*/
874 
875  for (tmp = GET_MAP_OB(op->map, op->x, op->y); tmp != NULL; tmp = tmp->above) {
876  int num_sections = 1;
877 
878  /* don't move DM */
879  if (QUERY_FLAG(tmp, FLAG_WIZ))
880  return;
881 
882  /* don't move parts of objects */
883  if (tmp->head)
884  continue;
885 
886  /* don't move floors or immobile objects */
887  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR) || QUERY_FLAG(tmp, FLAG_NO_PICK))
888  continue;
889 
890  /* count the object's sections */
891  for (tmp2 = tmp; tmp2 != NULL; tmp2 = tmp2->more)
892  num_sections++;
893 
894  /* I'm not sure if it makes sense to divide by num_sections - bigger
895  * objects should be harder to move, and we are moving the entire
896  * object, not just the head, so the total weight should be relevant.
897  */
898 
899  /* surface area? -tm */
900 
901  if (tmp->move_type&MOVE_FLYING)
902  frictionmod = 1; /* flying objects loose the friction modifier */
903  if (rndm(0, weight_move-1) > ((tmp->weight/num_sections)*frictionmod)) { /* move it. */
904  /* move_object is really for monsters, but looking at
905  * the move_object function, it appears that it should
906  * also be safe for objects.
907  * This does return if successful or not, but
908  * I don't see us doing anything useful with that information
909  * right now.
910  */
911 // LOG(llevDebug, "trying move\n");
912  if (op->direction){
913  move_object(tmp,absdir(op->direction));
914  }
915 
916  else {
917  (move_object(tmp, absdir(op->stats.sp)));
918 
919  }
920  }
921  else{
922 // LOG(llevDebug, "did not try move, don't know why\n");
923  }
924  }
925 }
archetype * find_archetype(const char *name)
Definition: arch.c:695
#define FLAG_IS_FLOOR
Definition: define.h:303
MoveType move_type
Definition: object.h:426
#define SP_BOLT
Definition: spells.h:78
void enter_exit(object *op, object *exit_ob)
Definition: server.c:722
sstring add_refcount(sstring str)
Definition: shstr.c:210
#define SPLINT
Definition: spells.h:165
#define SP_CONE
Definition: spells.h:81
method_ret common_pre_ob_move_on(object *trap, object *victim, object *originator)
Definition: common_apply.c:51
void object_copy_owner(object *op, object *clone)
Definition: object.c:690
uint16_t material
Definition: object.h:348
object * object_get_env_recursive(object *op)
Definition: object.c:366
static void move_bolt(object *op)
Definition: spell_effect.c:158
#define METHOD_ERROR
Definition: ob_methods.h:17
int8_t range
Definition: object.h:407
#define SP_MOVING_BALL
Definition: spells.h:109
#define SP_AURA
Definition: spells.h:120
void free_string(sstring str)
Definition: shstr.c:280
int16_t duration
Definition: object.h:405
short freearr_x[SIZEOFFREE]
Definition: object.c:65
#define DIRX(xyz)
Definition: define.h:479
static void animate_bomb(object *op)
Definition: spell_effect.c:456
uint8_t subtype
Definition: object.h:340
void check_spell_expiry(object *spell)
Definition: spell_util.c:2051
struct obj * above
Definition: object.h:288
method_ret ob_process(object *op)
Definition: ob_methods.c:68
#define object_was_destroyed(op, old_tag)
Definition: object.h:68
static void explosion(object *op)
Definition: spell_effect.c:315
int16_t sp
Definition: living.h:42
void cone_drop(object *op)
Definition: spell_attack.c:265
#define FLAG_REFLECTING
Definition: define.h:262
int reflwall(mapstruct *m, int x, int y, object *sp_op)
Definition: spell_util.c:509
struct archt * other_arch
Definition: object.h:415
int absdir(int d)
Definition: object.c:3655
Definition: object.h:467
#define SP_WORD_OF_RECALL
Definition: spells.h:92
int8_t Con
Definition: living.h:36
#define DIRY(xyz)
Definition: define.h:480
int adjust_dir(int dir, int destination_dir)
Definition: utils.c:453
short freearr_y[SIZEOFFREE]
Definition: object.c:71
void check_bullet(object *op)
Definition: spell_attack.c:217
char method_ret
Definition: ob_methods.h:14
int rndm(int min, int max)
Definition: utils.c:162
static void move_aura(object *aura)
Definition: spell_effect.c:747
void object_free_drop_inventory(object *ob)
Definition: object.c:1391
int16_t y
Definition: object.h:326
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.c:1935
int16_t maxhp
Definition: living.h:41
void object_update_turn_face(object *op)
Definition: object.c:1132
#define SP_BULLET
Definition: spells.h:79
static void check_spell_knockback(object *op)
Definition: spell_effect.c:862
#define FLAG_ALIVE
Definition: define.h:230
object * object_new(void)
Definition: object.c:1070
struct obj * spell
Definition: object.h:410
object * object_insert_in_ob(object *op, object *where)
Definition: object.c:2709
float speed_left
Definition: object.h:329
signed short int16_t
Definition: win32.h:160
const char * materialname
Definition: object.h:347
void register_move_on(int ob_type, move_on_func method)
Definition: ob_types.c:89
int32_t weight
Definition: object.h:366
#define METHOD_OK
Definition: ob_methods.h:15
#define SP_BOMB
Definition: spells.h:82
struct mapdef * map
Definition: object.h:297
#define MOVE_FLYING
Definition: define.h:410
static void move_swarm_spell(object *op)
Definition: spell_effect.c:677
int16_t dam
Definition: living.h:46
const char * name
Definition: object.h:311
struct obj * env
Definition: object.h:293
int hit_map(object *op, int dir, uint32_t type, int full_hit)
Definition: attack.c:322
uint8_t state
Definition: object.h:350
int8_t direction
Definition: object.h:335
static method_ret spell_effect_type_move_on(ob_methods *context, object *trap, object *victim, object *originator)
Definition: spell_effect.c:67
#define OB_TYPE_MOVE_BLOCK(ob1, type)
Definition: define.h:447
#define P_OUT_OF_MAP
Definition: map.h:251
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Definition: map.h:192
int get_random_dir(void)
Definition: utils.c:427
uint32_t tag_t
Definition: object.h:12
float speed
Definition: object.h:328
Definition: object.h:214
int on_same_map(const object *op1, const object *op2)
Definition: map.c:2658
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
#define FLAG_WIZ
Definition: define.h:231
#define SP_SWARM
Definition: spells.h:110
int ok_to_put_more(mapstruct *m, int16_t x, int16_t y, object *op, uint32_t immune_stop)
Definition: spell_util.c:569
void explode_bullet(object *op)
Definition: spell_attack.c:121
int16_t x
Definition: object.h:326
const char * skill
Definition: object.h:321
void save_throw_object(object *op, uint32_t type, object *originator)
Definition: attack.c:182
static void move_cone(object *op)
Definition: spell_effect.c:388
static void move_bullet(object *op)
Definition: spell_effect.c:261
void common_post_ob_move_on(object *trap, object *victim, object *originator)
Definition: common_apply.c:87
Definition: object.h:107
static method_ret spell_effect_type_process(ob_methods *context, object *op)
Definition: spell_effect.c:108
uint32_t attacktype
Definition: object.h:343
static void forklightning(object *op, object *tmp)
Definition: spell_effect.c:811
#define NUM_ANIMATIONS(ob)
Definition: global.h:177
tag_t count
Definition: object.h:299
living stats
Definition: object.h:369
int8_t Dex
Definition: living.h:36
uint8_t type
Definition: object.h:339
#define SP_MAGIC_MISSILE
Definition: spells.h:85
int move_object(object *op, int dir)
Definition: move.c:39
int out_of_map(mapstruct *m, int x, int y)
Definition: map.c:2313
#define FLAG_LIFESAVE
Definition: define.h:306
void register_process(int ob_type, process_func method)
Definition: ob_types.c:71
int fire_arch_from_position(object *op, object *caster, int16_t x, int16_t y, int dir, object *spell)
Definition: spell_util.c:670
void object_merge_spell(object *op, int16_t x, int16_t y)
Definition: object.c:1967
static void move_missile(object *op)
Definition: spell_effect.c:509
void init_type_spell_effect(void)
Definition: spell_effect.c:54
#define AT_MAGIC
Definition: attack.h:77
#define GET_MAP_OB(M, X, Y)
Definition: map.h:172
void object_copy(const object *src_ob, object *dest_ob)
Definition: object.c:871
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
Definition: map.c:310
struct obj * head
Definition: object.h:296
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
Definition: map.h:325
#define P_IS_ALIVE
Definition: map.h:237
#define FLAG_NO_PICK
Definition: define.h:239
int spell_find_dir(mapstruct *m, int x, int y, object *exclude)
Definition: spell_util.c:927
int hit_player(object *op, int dam, object *hitter, uint32_t type, int full_hit)
Definition: attack.c:1862
int16_t level
Definition: object.h:352
#define SP_EXPLOSION
Definition: spells.h:80
struct obj * more
Definition: object.h:295
object * arch_to_object(archetype *at)
Definition: arch.c:571
void object_update_speed(object *op)
Definition: object.c:1152
int32_t value
Definition: object.h:351
object * object_get_owner(object *op)
Definition: object.c:592
static void move_ball_spell(object *op)
Definition: spell_effect.c:578
void object_remove(object *op)
Definition: object.c:1668
static void execute_word_of_recall(object *op)
Definition: spell_effect.c:560