Crossfire Server, Trunk  R20513
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 
171  if (op->weight)
173 
174  if (!op->direction)
175  return;
176 
177  if (--op->range < 0) {
178  op->range = 0;
179  } else {
180  x = op->x+DIRX(op);
181  y = op->y+DIRY(op);
182  m = op->map;
183  mflags = get_map_flags(m, &m, x, y, &x, &y);
184 
185  if (mflags&P_OUT_OF_MAP)
186  return;
187 
188  /* We are about to run into something - we may bounce */
189  /* Calling reflwall is pretty costly, as it has to look at all the objects
190  * on the space. So only call reflwall if we think the data it returns
191  * will be useful.
192  */
193  if (OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, x, y))
194  || ((mflags&P_IS_ALIVE) && reflwall(m, x, y, op))) {
195  if (!QUERY_FLAG(op, FLAG_REFLECTING))
196  return;
197 
198  /* Since walls don't run diagonal, if the bolt is in
199  * one of 4 main directions, it just reflects back in the
200  * opposite direction. However, if the bolt is travelling
201  * on the diagonal, it is trickier - eg, a bolt travelling
202  * northwest bounces different if it hits a north/south
203  * wall (bounces to northeast) vs an east/west (bounces
204  * to the southwest.
205  */
206  if (op->direction&1) {
207  op->direction = absdir(op->direction+4);
208  } else {
209  int left, right;
210  int mflags;
211 
212  /* Need to check for P_OUT_OF_MAP: if the bolt is tavelling
213  * over a corner in a tiled map, it is possible that
214  * op->direction is within an adjacent map but either
215  * op->direction-1 or op->direction+1 does not exist.
216  */
217  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);
218 
219  left = (mflags&P_OUT_OF_MAP) ? 0 : OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, x, y));
220 
221  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);
222  right = (mflags&P_OUT_OF_MAP) ? 0 : OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, x, y));
223 
224  if (left == right)
225  op->direction = absdir(op->direction+4);
226  else if (left)
227  op->direction = absdir(op->direction+2);
228  else if (right)
229  op->direction = absdir(op->direction-2);
230  }
231  object_update_turn_face(op); /* A bolt *must *be IS_TURNABLE */
232  return;
233  } else { /* Create a copy of this object and put it ahead */
234  tmp = object_new();
235  object_copy(op, tmp);
236  tmp->speed_left = -0.1;
237  tmp = object_insert_in_map_at(tmp, op->map, op, 0, op->x+DIRX(op), op->y+DIRY(op));
238  /* To make up for the decrease at the top of the function */
239  tmp->duration++;
240 
241  /* New forking code. Possibly create forks of this object
242  * going off in other directions.
243  */
244 
245  if (rndm(0, 99) < tmp->stats.Dex) { /* stats.Dex % of forking */
246  forklightning(op, tmp);
247  }
248  /* In this way, the object left behind sticks on the space, but
249  * doesn't create any bolts that continue to move onward.
250  */
251  op->range = 0;
252  } /* copy object and move it along */
253  } /* if move bolt along */
254 }
255 
262 static void move_bullet(object *op) {
263  int16_t new_x, new_y;
264  int mflags;
265  mapstruct *m;
266 
267  /* Reached the end of its life - remove it */
268  if (--op->range <= 0) {
269  if (op->other_arch) {
270  explode_bullet(op);
271  } else {
272  object_remove(op);
274  }
275  return;
276  }
277 
278  new_x = op->x+DIRX(op);
279  new_y = op->y+DIRY(op);
280  m = op->map;
281  mflags = get_map_flags(m, &m, new_x, new_y, &new_x, &new_y);
282 
283  if (mflags&P_OUT_OF_MAP) {
284  object_remove(op);
286  return;
287  }
288 
289  if (!op->direction || OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, new_x, new_y))) {
290  if (op->other_arch) {
291  explode_bullet(op);
292  } else {
293  object_remove(op);
295  }
296  return;
297  }
298 
299  object_remove(op);
300  if ((op = object_insert_in_map_at(op, m, op, 0, new_x, new_y)) == NULL)
301  return;
302 
303  if (reflwall(op->map, op->x, op->y, op)) {
304  op->direction = absdir(op->direction+4);
306  } else {
307  check_bullet(op);
308  }
309 }
310 
316 static void explosion(object *op) {
317  object *tmp;
318  mapstruct *m = op->map;
319  int i;
320 
321  if (--(op->duration) < 0) {
322  object_remove(op);
324  return;
325  }
326  hit_map(op, 0, op->attacktype, 0);
327 // if (op->weight)
329 
330  if (op->range > 0) {
331  for (i = 1; i < 9; i++) {
332  int16_t dx, dy;
333  int16_t Dx, Dy;
334  dx = op->x+freearr_x[i];
335  dy = op->y+freearr_y[i];
336  /* ok_to_put_more already does things like checks for walls,
337  * out of map, etc.
338  */
339  if (ok_to_put_more(op->map, dx, dy, op, op->attacktype)) {
340  tmp = object_new();
341  object_copy(op, tmp);
342  tmp->state = 0;
343  tmp->speed_left = -0.21;
344  tmp->range--;
345  tmp->value = 0;
346  Dx=dx-op->x;
347  Dy=dy-op->y;
348  if (Dx==-1 && Dy==-1){
349  tmp->direction=8;
350  }
351  if (Dx==0 && Dy==-1){
352  tmp->direction=1;
353  }
354  if (Dx==1 && Dy==-1){
355  tmp->direction=2;
356  }
357  if (Dx==1 && Dy==0){
358  tmp->direction=3;
359  }
360  if (Dx==1 && Dy==1){
361  tmp->direction=4;
362  }
363  if (Dx==0 && Dy==1){
364  tmp->direction=5;
365  }
366  if (Dx==-1 && Dy==-1){
367  tmp->direction=6;
368  }
369  if (Dx==-1 && Dy==0){
370  tmp->direction=7;
371  }
372 
373  object_insert_in_map_at(tmp, m, op, 0, dx, dy);
374 
375  }
376  }
377  /* Reset range so we don't try to propogate anymore.
378  * Call object_merge_spell() to see if we can merge with another
379  * spell on the space.
380  */
381  op->range = 0;
382  object_merge_spell(op, op->x, op->y);
383  }
384 }
385 
390 static void move_cone(object *op) {
391  int i;
392  tag_t tag;
393 
394  /* if no map then hit_map will crash so just ignore object */
395  if (!op->map) {
396  LOG(llevError, "Tried to move_cone object %s without a map.\n", op->name ? op->name : "unknown");
397  op->speed = 0;
399  return;
400  }
401 
402  /* lava saves it's life, but not yours :) */
403  if (QUERY_FLAG(op, FLAG_LIFESAVE)) {
404  hit_map(op, 0, op->attacktype, 0);
405  return;
406  }
407 
408  tag = op->count;
409  hit_map(op, 0, op->attacktype, 0);
410 
411  /* Check to see if we should push anything.
412  * Spell objects with weight push whatever they encounter to some
413  * degree.
414  */
415  if (op->weight)
417 
418  if (object_was_destroyed(op, tag))
419  return;
420 
421  if ((op->duration--) < 0) {
422  object_remove(op);
424  return;
425  }
426 
427  /* Object has hit maximum range, so don't have it move
428  * any further. When the duration above expires,
429  * then the object will get removed.
430  */
431  if (--op->range < 0) {
432  op->range = 0; /* just so it doesn't wrap */
433  return;
434  }
435 
436  for (i = -1; i < 2; i++) {
437  int16_t x = op->x+freearr_x[absdir(op->stats.sp+i)];
438  int16_t y = op->y+freearr_y[absdir(op->stats.sp+i)];
439 
440  if (ok_to_put_more(op->map, x, y, op, op->attacktype)) {
441  object *tmp = object_new();
442 
443  object_copy(op, tmp);
444  tmp->duration = op->duration+1;
445 
446  /* Use for spell tracking - see ok_to_put_more() */
447  tmp->stats.maxhp = op->stats.maxhp;
448  object_insert_in_map_at(tmp, op->map, op, 0, x, y);
449  if (tmp->other_arch)
450  cone_drop(tmp);
451  }
452  }
453 }
454 
459 static void animate_bomb(object *op) {
460  int i;
461  object *env, *tmp;
462  archetype *at;
463 
464  if (op->state != NUM_ANIMATIONS(op)-1)
465  return;
466 
467  env = object_get_env_recursive(op);
468 
469  if (op->env) {
470  if (env->map == NULL)
471  return;
472 
473  object_remove(op);
474  if ((op = object_insert_in_map_at(op, env->map, op, 0, env->x, env->y)) == NULL)
475  return;
476  }
477 
478  /* This copies a lot of the code from the fire bullet,
479  * but using the cast_bullet isn't really feasible,
480  * so just set up the appropriate values.
481  */
482  at = find_archetype(SPLINT);
483  if (at) {
484  for (i = 1; i < 9; i++) {
485  if (out_of_map(op->map, op->x+freearr_x[i], op->y+freearr_x[i]))
486  continue;
487  tmp = arch_to_object(at);
488  tmp->direction = i;
489  tmp->range = op->range;
490  tmp->stats.dam = op->stats.dam;
491  tmp->duration = op->duration;
492  tmp->attacktype = op->attacktype;
493  object_copy_owner(tmp, op);
494  if (op->skill && op->skill != tmp->skill) {
495  if (tmp->skill)
496  free_string(tmp->skill);
497  tmp->skill = add_refcount(op->skill);
498  }
500  object_insert_in_map_at(tmp, op->map, op, 0, op->x+freearr_x[i], op->y+freearr_x[i]);
501  ob_process(tmp);
502  }
503  }
504 
505  explode_bullet(op);
506 }
507 
512 static void move_missile(object *op) {
513  int i, mflags;
514  int16_t new_x, new_y;
515  mapstruct *m;
516 
517  if (op->range-- <= 0) {
518  object_remove(op);
520  return;
521  }
522 
523  /* call is required to potentially clean owner, but we don't care for the result */
524  object_get_owner(op);
525 
526  new_x = op->x+DIRX(op);
527  new_y = op->y+DIRY(op);
528 
529  mflags = get_map_flags(op->map, &m, new_x, new_y, &new_x, &new_y);
530 
531  if (!(mflags&P_OUT_OF_MAP)
532  && ((mflags&P_IS_ALIVE) || OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, new_x, new_y)))) {
533  tag_t tag = op->count;
534 
535  hit_map(op, op->direction, AT_MAGIC, 1);
536  /* Basically, missile only hits one thing then goes away.
537  * we need to remove it if someone hasn't already done so.
538  */
539  if (!object_was_destroyed(op, tag)) {
540  object_remove(op);
542  }
543  return;
544  }
545 
546  object_remove(op);
547  if (!op->direction || (mflags&P_OUT_OF_MAP)) {
549  return;
550  }
551  i = spell_find_dir(m, new_x, new_y, object_get_owner(op));
552  if (i > 0 && i != op->direction) {
553  op->direction = adjust_dir(op->direction, i);
555  }
556  object_insert_in_map_at(op, m, op, 0, new_x, new_y);
557 }
558 
563 static void execute_word_of_recall(object *op) {
564  object *wor = op;
565 
566  while (op != NULL && op->type != PLAYER)
567  op = op->env;
568 
569  if (op != NULL && op->map) {
570  if ((get_map_flags(op->map, NULL, op->x, op->y, NULL, NULL)&P_NO_CLERIC) && (!QUERY_FLAG(op, FLAG_WIZCAST)))
572  "You feel something fizzle inside you.");
573  else
574  enter_exit(op, wor);
575  }
576  object_remove(wor);
578 }
579 
585 static void move_ball_spell(object *op) {
586  int i, j, dam_save, dir, mflags;
587  int16_t nx, ny, hx, hy;
588  object *owner;
589  mapstruct *m;
590 
591  owner = object_get_owner(op);
592 
593  /* the following logic makes sure that the ball doesn't move into a wall,
594  * and makes sure that it will move along a wall to try and get at it's
595  * victim. The block immediately below more or less chooses a random
596  * offset to move the ball, eg, keep it mostly on course, with some
597  * deviations.
598  */
599 
600  dir = 0;
601  j = rndm(0, 1);
602  for (i = 1; i <= 9; i++) {
603  /* i bit 0: alters sign of offset
604  * other bits (i/2): absolute value of offset
605  */
606 
607  int offset = ((i^j)&1) ? (i/2) : -(i/2);
608  int tmpdir = absdir(op->direction+offset);
609 
610  nx = op->x+freearr_x[tmpdir];
611  ny = op->y+freearr_y[tmpdir];
612  if (!(get_map_flags(op->map, &m, nx, ny, &nx, &ny)&P_OUT_OF_MAP)
613  && !(OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, nx, ny)))) {
614  dir = tmpdir;
615  break;
616  }
617  }
618  if (dir == 0) {
619  nx = op->x;
620  ny = op->y;
621  m = op->map;
622  }
623 
624  object_remove(op);
625  object_insert_in_map_at(op, m, op, 0, nx, ny);
626 
627  dam_save = op->stats.dam; /* save the original dam: we do halfdam on
628  surrounding squares */
629 
630  /* loop over current square and neighbors to hit.
631  * if this has an other_arch field, we insert that in
632  * the surround spaces.
633  */
634  for (j = 0; j < 9; j++) {
635  object *new_ob;
636 
637  hx = nx+freearr_x[j];
638  hy = ny+freearr_y[j];
639 
640  m = op->map;
641  mflags = get_map_flags(m, &m, hx, hy, &hx, &hy);
642 
643  if (mflags&P_OUT_OF_MAP)
644  continue;
645 
646  /* first, don't ever, ever hit the owner. Don't hit out
647  * of the map either.
648  */
649 
650  if ((mflags&P_IS_ALIVE) && (!owner || owner->x != hx || owner->y != hy || !on_same_map(owner, op))) {
651  if (j)
652  op->stats.dam = dam_save/2;
653  hit_map(op, j, op->attacktype, 1);
654  }
655 
656  /* insert the other arch */
657  if (op->other_arch && !(OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, hx, hy)))) {
658  new_ob = arch_to_object(op->other_arch);
659  object_insert_in_map_at(new_ob, m, op, 0, hx, hy);
660  }
661  }
662 
663  /* restore to the center location and damage*/
664  op->stats.dam = dam_save;
665 
666  i = spell_find_dir(op->map, op->x, op->y, object_get_owner(op));
667  if (i >= 0) { /* we have a preferred direction! */
668  op->direction = adjust_dir(op->direction, i);
669  if (rndm(0, 3) != 0)
670  op->direction = adjust_dir(op->direction, i);
671  if (rndm(0, 3) == 0)
672  op->direction = adjust_dir(op->direction, i);
673  }
674 }
675 
676 /*
677  * This is an implementation of the swarm spell. It was written for meteor
678  * swarm, but it could be used for any swarm. A swarm spell is a special type
679  * of object that casts swarms of other types of spells. Which spell it casts
680  * is flexible. It fires the spells from a set of squares surrounding the
681  * caster, in a given direction.
682  * @param op The spell effect.
683  */
684 static void move_swarm_spell(object *op) {
685  static int cardinal_adjust[9] = { -3, -2, -1, 0, 0, 0, 1, 2, 3 };
686  static int diagonal_adjust[10] = { -3, -2, -2, -1, 0, 0, 1, 2, 2, 3 };
687  int16_t target_x, target_y, origin_x, origin_y;
688  int basedir, adjustdir;
689  mapstruct *m;
690  object *owner;
691 
692  owner = object_get_owner(op);
693  if (op->duration == 0 || owner == NULL || owner->x != op->x || owner->y != op->y) {
694  object_remove(op);
696  return;
697  }
698  op->duration--;
699 
700  basedir = op->direction;
701  if (basedir == 0) {
702  /* spray in all directions! 8) */
703  basedir = get_random_dir();
704  }
705 
706  /* new offset calculation to make swarm element distribution
707  * more uniform
708  */
709  if (op->duration) {
710  if (basedir&1) {
711  adjustdir = cardinal_adjust[rndm(0, 8)];
712  } else {
713  adjustdir = diagonal_adjust[rndm(0, 9)];
714  }
715  } else {
716  adjustdir = 0; /* fire the last one from forward. */
717  }
718 
719  target_x = op->x+freearr_x[absdir(basedir+adjustdir)];
720  target_y = op->y+freearr_y[absdir(basedir+adjustdir)];
721 
722  /* back up one space so we can hit point-blank targets, but this
723  * necessitates extra out_of_map check below
724  */
725  origin_x = target_x-freearr_x[basedir];
726  origin_y = target_y-freearr_y[basedir];
727 
728 
729  /* spell pointer is set up for the spell this casts. Since this
730  * should just be a pointer to the spell in some inventory,
731  * it is unlikely to disappear by the time we need it. However,
732  * do some sanity checking anyways.
733  */
734 
735  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)) {
736  /* Bullet spells have a bunch more customization that needs to be done */
737  if (op->spell->subtype == SP_BULLET)
738  fire_arch_from_position(owner, op, origin_x+freearr_x[basedir], origin_y+freearr_y[basedir], basedir, op->spell);
739  else if (op->spell->subtype == SP_MAGIC_MISSILE)
740  fire_arch_from_position(owner, op, origin_x, origin_y, basedir, op->spell);
741  }
742 }
743 
754 static void move_aura(object *aura) {
755  int i, mflags;
756  object *env;
757  mapstruct *m;
758 
759  /* auras belong in inventories */
760  env = aura->env;
761 
762  /* no matter what we've gotta remove the aura...
763  * we'll put it back if its time isn't up.
764  */
765  object_remove(aura);
766 
767  /* exit if we're out of gas */
768  if (aura->duration-- < 0) {
770  return;
771  }
772 
773  /* auras only exist in inventories */
774  if (env == NULL || env->map == NULL) {
776  return;
777  }
778 
779  /* we need to jump out of the inventory for a bit
780  * in order to hit the map conveniently.
781  */
782  object_insert_in_map_at(aura, env->map, aura, 0, env->x, env->y);
783 
784  for (i = 1; i < 9; i++) {
785  int16_t nx, ny;
786 
787  nx = aura->x+freearr_x[i];
788  ny = aura->y+freearr_y[i];
789  mflags = get_map_flags(env->map, &m, nx, ny, &nx, &ny);
790 
791  /* Consider the movement type of the person with the aura as
792  * movement type of the aura. Eg, if the player is flying, the aura
793  * is flying also, if player is walking, it is on the ground, etc.
794  */
795  if (!(mflags&P_OUT_OF_MAP) && !(OB_TYPE_MOVE_BLOCK(env, GET_MAP_MOVE_BLOCK(m, nx, ny)))) {
796  hit_map(aura, i, aura->attacktype, 0);
797 
798  if (aura->other_arch) {
799  object *new_ob;
800 
801  new_ob = arch_to_object(aura->other_arch);
802  object_insert_in_map_at(new_ob, m, aura, 0, nx, ny);
803  }
804  }
805  }
806 
807  /* put the aura back in the player's inventory */
808  object_remove(aura);
809  object_insert_in_ob(aura, env);
810  check_spell_expiry(aura);
811 }
812 
818 static void forklightning(object *op, object *tmp) {
819  int new_dir = 1; /* direction or -1 for left, +1 for right 0 if no new bolt */
820  int t_dir; /* stores temporary dir calculation */
821  mapstruct *m;
822  int16_t sx, sy;
823  object *new_bolt;
824 
825  /* pick a fork direction. tmp->stats.Con is the left bias
826  * i.e., the chance in 100 of forking LEFT
827  * Should start out at 50, down to 25 for one already going left
828  * down to 0 for one going 90 degrees left off original path
829  */
830 
831  if (rndm(0, 99) < tmp->stats.Con) /* fork left */
832  new_dir = -1;
833 
834  /* check the new dir for a wall and in the map*/
835  t_dir = absdir(tmp->direction+new_dir);
836 
837  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)
838  return;
839 
840  if (OB_TYPE_MOVE_BLOCK(tmp, GET_MAP_MOVE_BLOCK(m, sx, sy)))
841  return;
842 
843  /* OK, we made a fork */
844  new_bolt = object_new();
845 
846  object_copy(tmp, new_bolt);
847 
848  /* reduce chances of subsequent forking */
849  new_bolt->stats.Dex -= 10;
850  tmp->stats.Dex -= 10; /* less forks from main bolt too */
851  new_bolt->stats.Con += 25*new_dir; /* adjust the left bias */
852  new_bolt->speed_left = -0.1;
853  new_bolt->direction = t_dir;
854  new_bolt->duration++;
855  new_bolt->stats.dam /= 2; /* reduce daughter bolt damage */
856  new_bolt->stats.dam++;
857  tmp->stats.dam /= 2; /* reduce father bolt damage */
858  tmp->stats.dam++;
859  new_bolt = object_insert_in_map_at(new_bolt, m, op, 0, sx, sy);
860  object_update_turn_face(new_bolt);
861 }
862 
869 static void check_spell_knockback(object *op) {
870  object *tmp, *tmp2; /* object on the map */
871  int weight_move;
872  int frictionmod = 2; /*poor man's physics - multipy targets weight by this amount */
873 
874  if (!op->weight) { /*shouldn't happen but if cone object has no weight drop out*/
875  LOG(llevDebug, "DEBUG: arch weighs nothing in check_spell_knockback\n");
876  return;
877  } else {
878  weight_move = op->weight+(op->weight*op->level)/3;
879  /*LOG(llevDebug, "DEBUG: arch weighs %d and masses %d (%s,level %d)\n", op->weight, weight_move, op->name, op->level);*/
880  }
881 
882  for (tmp = GET_MAP_OB(op->map, op->x, op->y); tmp != NULL; tmp = tmp->above) {
883  int num_sections = 1;
884 
885  /* don't move DM */
886  if (QUERY_FLAG(tmp, FLAG_WIZ))
887  return;
888 
889  /* don't move parts of objects */
890  if (tmp->head)
891  continue;
892 
893  /* don't move floors or immobile objects */
894  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR) || QUERY_FLAG(tmp, FLAG_NO_PICK))
895  continue;
896 
897  /* count the object's sections */
898  for (tmp2 = tmp; tmp2 != NULL; tmp2 = tmp2->more)
899  num_sections++;
900 
901  /* I'm not sure if it makes sense to divide by num_sections - bigger
902  * objects should be harder to move, and we are moving the entire
903  * object, not just the head, so the total weight should be relevant.
904  */
905 
906  /* surface area? -tm */
907 
908  if (tmp->move_type&MOVE_FLYING)
909  frictionmod = 1; /* flying objects loose the friction modifier */
910  if (rndm(0, weight_move-1) > ((tmp->weight/num_sections)*frictionmod)) { /* move it. */
911  /* move_object is really for monsters, but looking at
912  * the move_object function, it appears that it should
913  * also be safe for objects.
914  * This does return if successful or not, but
915  * I don't see us doing anything useful with that information
916  * right now.
917  */
918 // LOG(llevDebug, "trying move\n");
919  if (op->direction){
920  move_object(tmp,absdir(op->direction));
921  }
922 
923  else {
924  (move_object(tmp, absdir(op->stats.sp)));
925 
926  }
927  }
928  else{
929 // LOG(llevDebug, "did not try move, don't know why\n");
930  }
931  }
932 }
Error, serious thing.
Definition: logger.h:11
Sound-related defines.
archetype * find_archetype(const char *name)
Finds, using the hashtable, which archetype matches the given name.
Definition: arch.c:695
#define FLAG_IS_FLOOR
Can&#39;t see what&#39;s underneath this object.
Definition: define.h:303
MoveType move_type
Type of movement this object uses.
Definition: object.h:424
#define SP_BOLT
Definition: spells.h:78
void enter_exit(object *op, object *exit_ob)
Tries to move &#39;op&#39; to exit_ob.
Definition: server.c:706
sstring add_refcount(sstring str)
This will increase the refcount of the string str.
Definition: shstr.c:210
#define SPLINT
Definition: spells.h:165
Typedefs for ob_methods.
Definition: ob_methods.h:45
#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)
Set the owner to clone&#39;s current owner and set the skill and experience objects to clone&#39;s objects (t...
Definition: object.c:657
uint16_t material
What materials this object consist of.
Definition: object.h:347
object * object_get_env_recursive(object *op)
Utility function.
Definition: object.c:333
static void move_bolt(object *op)
Moves bolt &#39;op&#39;.
Definition: spell_effect.c:158
#define METHOD_ERROR
Definition: ob_methods.h:17
int8_t range
Range of the spell.
Definition: object.h:405
#define SP_MOVING_BALL
Definition: spells.h:109
#define SP_AURA
Definition: spells.h:120
#define MSG_TYPE_SPELL
Spell related info.
Definition: newclient.h:387
#define MSG_TYPE_SPELL_FAILURE
Spell failure messages.
Definition: newclient.h:628
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.c:280
int16_t duration
How long the spell lasts.
Definition: object.h:403
short freearr_x[SIZEOFFREE]
X offset when searching around a spot.
Definition: object.c:65
#define DIRX(xyz)
Definition: define.h:477
static void animate_bomb(object *op)
This handles an exploding bomb.
Definition: spell_effect.c:459
uint8_t subtype
Subtype of object.
Definition: object.h:339
void check_spell_expiry(object *spell)
Checks if player should be warned of soon expiring spell.
Definition: spell_util.c:2031
struct obj * above
Pointer to the object stacked above this one.
Definition: object.h:288
method_ret ob_process(object *op)
Processes an object, giving it the opportunity to move or react.
Definition: ob_methods.c:62
#define object_was_destroyed(op, old_tag)
Checks if an object still exists.
Definition: object.h:68
static void explosion(object *op)
Expands an explosion.
Definition: spell_effect.c:316
int16_t sp
Spell points.
Definition: living.h:41
void cone_drop(object *op)
Drops an object based on what is in the cone&#39;s "other_arch".
Definition: spell_attack.c:265
#define FLAG_REFLECTING
Object reflects from walls (lightning)
Definition: define.h:262
Global type definitions and header inclusions.
int reflwall(mapstruct *m, int x, int y, object *sp_op)
Decides weither the (spell-)object sp_op will be reflected from the given mapsquare.
Definition: spell_util.c:511
struct archt * other_arch
Pointer used for various things - mostly used for what this objects turns into or what this object cr...
Definition: object.h:413
int absdir(int d)
Computes an absolute direction.
Definition: object.c:3637
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Sends message to player(s).
Definition: main.c:310
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:465
#define SP_WORD_OF_RECALL
Definition: spells.h:92
int8_t Con
Definition: living.h:35
#define DIRY(xyz)
Definition: define.h:478
int adjust_dir(int dir, int destination_dir)
Adjusts a given direction by +/-1 towards a destination direction.
Definition: utils.c:452
short freearr_y[SIZEOFFREE]
Y offset when searching around a spot.
Definition: object.c:71
void check_bullet(object *op)
Checks to see what op should do, given the space it is on (eg, explode, damage player, etc).
Definition: spell_attack.c:217
char method_ret
Define some standard return values for callbacks which don&#39;t need to return any other results...
Definition: ob_methods.h:14
int rndm(int min, int max)
Returns a number between min and max.
Definition: utils.c:161
static void move_aura(object *aura)
Process an aura.
Definition: spell_effect.c:754
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects, and puts it on the list of free objects.
Definition: object.c:1368
int16_t y
Position in the map for this object.
Definition: object.h:326
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Same as object_insert_in_map() except it handle separate coordinates and do a clean job preparing mul...
Definition: object.c:1921
int16_t maxhp
Max hit points.
Definition: living.h:40
void object_update_turn_face(object *op)
If an object with the IS_TURNABLE() flag needs to be turned due to the closest player being on the ot...
Definition: object.c:1109
#define SP_BULLET
Definition: spells.h:79
static void check_spell_knockback(object *op)
Checks to see if a spell pushes objects as well as flies over and damages them (only used for cones f...
Definition: spell_effect.c:869
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:230
object * object_new(void)
Grabs an object from the list of unused objects, makes sure it is initialised, and returns it...
Definition: object.c:1037
struct obj * spell
Spell that was being cast.
Definition: object.h:408
object * object_insert_in_ob(object *op, object *where)
This function inserts the object op in the linked list inside the object environment.
Definition: object.c:2690
float speed_left
How much speed is left to spend this round.
Definition: object.h:329
signed short int16_t
Definition: win32.h:160
const char * materialname
Specific material name.
Definition: object.h:346
void register_move_on(int ob_type, move_on_func method)
Registers the move_on method for the given type.
Definition: ob_types.c:89
int32_t weight
Attributes of the object.
Definition: object.h:365
#define METHOD_OK
Definition: ob_methods.h:15
#define SP_BOMB
Definition: spells.h:82
struct mapdef * map
Pointer to the map in which this object is present.
Definition: object.h:297
#define MOVE_FLYING
Combo of fly_low and fly_high.
Definition: define.h:410
static void move_swarm_spell(object *op)
Definition: spell_effect.c:684
int16_t dam
How much damage this object does when hitting.
Definition: living.h:45
const char * name
The name of the object, obviously...
Definition: object.h:311
struct obj * env
Pointer to the object which is the environment.
Definition: object.h:293
int hit_map(object *op, int dir, uint32_t type, int full_hit)
Attack a spot on the map.
Definition: attack.c:320
uint8_t state
How the object was last drawn (animation)
Definition: object.h:349
int8_t direction
Means the object is moving that way.
Definition: object.h:334
static method_ret spell_effect_type_move_on(ob_methods *context, object *trap, object *victim, object *originator)
Move on this Spell Effect object.
Definition: spell_effect.c:67
#define OB_TYPE_MOVE_BLOCK(ob1, type)
Basic macro to see if if ob1 can not move onto a space based on the &#39;type&#39; move_block parameter Add c...
Definition: define.h:447
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:251
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Gets the blocking state of a square.
Definition: map.h:192
int get_random_dir(void)
Returns a random direction (1..8).
Definition: utils.c:426
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:12
float speed
The overall speed of this object.
Definition: object.h:328
See Spell.
Definition: object.h:214
int on_same_map(const object *op1, const object *op2)
Checks whether 2 objects are on the same map or not.
Definition: map.c:2627
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
#define FLAG_WIZ
Object has special privilegies.
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)
Returns true if it is ok to put spell op on the space/may provided.
Definition: spell_util.c:571
void explode_bullet(object *op)
Causes an object to explode, eg, a firebullet, poison cloud ball, etc.
Definition: spell_attack.c:121
int16_t x
Definition: object.h:326
const char * skill
Name of the skill this object uses/grants.
Definition: object.h:321
Object type variables.
void save_throw_object(object *op, uint32_t type, object *originator)
Object is attacked with some attacktype (fire, ice, ...).
Definition: attack.c:156
static void move_cone(object *op)
Causes cone object &#39;op&#39; to move a space/hit creatures.
Definition: spell_effect.c:390
static void move_bullet(object *op)
Moves bullet &#39;op&#39;.
Definition: spell_effect.c:262
void common_post_ob_move_on(object *trap, object *victim, object *originator)
Definition: common_apply.c:87
See Player.
Definition: object.h:107
static method_ret spell_effect_type_process(ob_methods *context, object *op)
Handle ob_process for all SPELL_EFFECT objects.
Definition: spell_effect.c:108
uint32_t attacktype
Bitmask of attacks this object does.
Definition: object.h:342
static void forklightning(object *op, object *tmp)
Causes op to fork.
Definition: spell_effect.c:818
#define NUM_ANIMATIONS(ob)
Definition: global.h:179
tag_t count
Unique object number for this object.
Definition: object.h:299
living stats
Str, Con, Dex, etc.
Definition: object.h:368
#define FLAG_WIZCAST
The wizard can cast spells in no-magic area.
Definition: define.h:290
int8_t Dex
Definition: living.h:35
Only for debugging purposes.
Definition: logger.h:13
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:338
#define SP_MAGIC_MISSILE
Definition: spells.h:85
int move_object(object *op, int dir)
Try to move op in the direction "dir".
Definition: move.c:39
int out_of_map(mapstruct *m, int x, int y)
this returns TRUE if the coordinates (x,y) are out of map m.
Definition: map.c:2294
#define FLAG_LIFESAVE
Saves a players&#39; life once, then destr.
Definition: define.h:306
void register_process(int ob_type, process_func method)
Registers the process method for the given type.
Definition: ob_types.c:71
int fire_arch_from_position(object *op, object *caster, int16_t x, int16_t y, int dir, object *spell)
Fires an archetype.
Definition: spell_util.c:672
void object_merge_spell(object *op, int16_t x, int16_t y)
This sees if there are any objects on the space that can merge with op.
Definition: object.c:1953
static void move_missile(object *op)
Move a missle object.
Definition: spell_effect.c:512
void init_type_spell_effect(void)
Initializer for the SPELL_EFFECT object type.
Definition: spell_effect.c:54
#define AT_MAGIC
Definition: attack.h:77
#define GET_MAP_OB(M, X, Y)
Gets the bottom object on a map.
Definition: map.h:172
void object_copy(const object *src_ob, object *dest_ob)
Copy object first frees everything allocated by the second object, and then copies the contents of th...
Definition: object.c:838
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
This rolls up wall, blocks_magic, blocks_view, etc, all into one function that just returns a P_...
Definition: map.c:302
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:245
struct obj * head
Points to the main object of a large body.
Definition: object.h:296
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.c:51
This is a game-map.
Definition: map.h:325
#define P_IS_ALIVE
Something alive is on this space.
Definition: map.h:237
#define FLAG_NO_PICK
Object can&#39;t be picked up.
Definition: define.h:239
int spell_find_dir(mapstruct *m, int x, int y, object *exclude)
Search what direction a spell should go in, first the center square then some close squares in the gi...
Definition: spell_util.c:929
int hit_player(object *op, int dam, object *hitter, uint32_t type, int full_hit)
Object is attacked by something.
Definition: attack.c:1861
Object type functions and variables.
int16_t level
Level of creature or object.
Definition: object.h:351
#define SP_EXPLOSION
Definition: spells.h:80
struct obj * more
Pointer to the rest of a large body of objects.
Definition: object.h:295
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.c:571
void object_update_speed(object *op)
Updates the speed of an object.
Definition: object.c:1129
int32_t value
How much money it is worth (or contains)
Definition: object.h:350
object * object_get_owner(object *op)
Returns the object which this object marks as being the owner.
Definition: object.c:559
static void move_ball_spell(object *op)
This handles ball type spells that just sort of wander about.
Definition: spell_effect.c:585
#define P_NO_CLERIC
No clerical spells cast here.
Definition: map.h:238
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to...
Definition: object.c:1654
static void execute_word_of_recall(object *op)
Handles the actual word of recalling.
Definition: spell_effect.c:563