Crossfire Server, Trunk
spell_attack.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
24 #include "global.h"
25 
26 #include <assert.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include "object.h"
31 #include "living.h"
32 #include "sproto.h"
33 #include "spells.h"
34 #include "sounds.h"
35 
36 /***************************************************************************
37  * BOLT CODE
38  ***************************************************************************/
39 
61 int fire_bolt(object *op, object *caster, int dir, object *spob) {
62  object *tmp = NULL;
63  int mflags;
64 
65  if (!spob->other_arch)
66  return 0;
67 
68  tmp = arch_to_object(spob->other_arch);
69  if (tmp == NULL)
70  return 0;
71 
72  /* peterm: level dependency for bolts */
73  tmp->stats.dam = spob->stats.dam+SP_level_dam_adjust(caster, spob);
74  tmp->attacktype = spob->attacktype;
75  if (spob->slaying)
76  tmp->slaying = add_refcount(spob->slaying);
77  tmp->range = spob->range+SP_level_range_adjust(caster, spob);
78  tmp->duration = spob->duration+SP_level_duration_adjust(caster, spob);
79  tmp->stats.Dex = spob->stats.Dex;
80  tmp->stats.Con = spob->stats.Con;
81 
82  tmp->direction = dir;
84 
86  set_spell_skill(op, caster, spob, tmp);
87 
88  mflags = get_map_flags(op->map, &tmp->map, op->x+DIRX(tmp), op->y+DIRY(tmp), &tmp->x, &tmp->y);
89  if (mflags&P_OUT_OF_MAP) {
91  return 0;
92  }
93  if (OB_TYPE_MOVE_BLOCK(tmp, GET_MAP_MOVE_BLOCK(tmp->map, tmp->x, tmp->y))) {
96  return 0;
97  }
98  tmp->direction = absdir(tmp->direction+4);
99  tmp->map = op->map;
100  tmp->x = op->x;
101  tmp->y = op->y;
102  }
103  tmp = object_insert_in_map_at(tmp, tmp->map, op, 0, tmp->x, tmp->y);
104  if (tmp != NULL)
105  ob_process(tmp);
106  return 1;
107 }
108 
109 /***************************************************************************
110  *
111  * BULLET/BALL CODE
112  *
113  ***************************************************************************/
114 
121 void explode_bullet(object *op) {
122  tag_t op_tag = op->count;
123  object *tmp, *owner;
124 
125  if (op->other_arch == NULL) {
126  LOG(llevError, "BUG: explode_bullet(): op without other_arch\n");
127  object_remove(op);
129  return;
130  }
131 
132  if (op->env) {
133  object *env;
134 
136  if (env->map == NULL || out_of_map(env->map, env->x, env->y)) {
137  LOG(llevError, "BUG: explode_bullet(): env out of map\n");
138  object_remove(op);
140  return;
141  }
142  object_remove(op);
144  } else if (out_of_map(op->map, op->x, op->y)) {
145  LOG(llevError, "BUG: explode_bullet(): op out of map\n");
146  object_remove(op);
148  return;
149  }
150 
151  if (op->attacktype) {
152  hit_map(op, 0, op->attacktype, 1);
153  if (object_was_destroyed(op, op_tag))
154  return;
155  }
156 
157  /* other_arch contains what this explodes into */
158  tmp = arch_to_object(op->other_arch);
159 
161  if (tmp->skill)
162  FREE_AND_CLEAR_STR(tmp->skill);
163  if (op->skill)
164  tmp->skill = add_refcount(op->skill);
165 
166  owner = object_get_owner(op);
167  if ((tmp->attacktype&AT_HOLYWORD || tmp->attacktype&AT_GODPOWER) && owner && !tailor_god_spell(tmp, owner)) {
168  object_remove(op);
170  return;
171  }
172 
173  /* special for bombs - it actually has sane values for these */
174  if (op->type == SPELL_EFFECT && op->subtype == SP_BOMB) {
175  tmp->attacktype = op->attacktype;
176  tmp->range = op->range;
177  tmp->stats.dam = op->stats.dam;
178  tmp->duration = op->duration;
179  } else {
180  if (op->attacktype&AT_MAGIC)
181  tmp->attacktype |= AT_MAGIC;
182  /* Spell doc describes what is going on here */
183  tmp->stats.dam = op->dam_modifier;
184  tmp->range = op->stats.maxhp;
185  tmp->duration = op->stats.hp;
186  }
187 
188  /* Used for spell tracking - just need a unique val for this spell -
189  * the count of the parent should work fine.
190  */
191  tmp->stats.maxhp = op->count;
192  if (tmp->stats.maxhp == 0)
193  tmp->stats.maxhp = 1;
194 
195  /* Set direction of cone explosion */
196  if (tmp->type == SPELL_EFFECT && tmp->subtype == SP_CONE)
197  tmp->stats.sp = op->direction;
198 
199  /* Prevent recursion */
200  op->move_on = 0;
201 
202  object_insert_in_map_at(tmp, op->map, op, 0, op->x, op->y);
203  /* remove the firebullet */
204  if (!object_was_destroyed(op, op_tag)) {
205  object_remove(op);
207  }
208 }
209 
217 void check_bullet(object *op) {
218  tag_t op_tag = op->count, tmp_tag;
219  int dam, mflags;
220  mapstruct *m;
221  int16_t sx, sy;
222 
223  mflags = get_map_flags(op->map, &m, op->x, op->y, &sx, &sy);
224 
225  if (!(mflags&P_IS_ALIVE) && !OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, sx, sy)))
226  return;
227 
228  if (op->other_arch) {
229  /* explode object will also remove op */
231  return;
232  }
233 
234  /* If nothing alive on this space, no reason to do anything further */
235  if (!(mflags&P_IS_ALIVE))
236  return;
237 
238  FOR_MAP_PREPARE(op->map, op->x, op->y, tmp) {
239  if (QUERY_FLAG(tmp, FLAG_ALIVE)) {
240  tmp_tag = tmp->count;
241  dam = hit_player(tmp, op->stats.dam, op, op->attacktype, 1);
242  if (object_was_destroyed(op, op_tag) || !object_was_destroyed(tmp, tmp_tag) || (op->stats.dam -= dam) < 0) {
243  if (!QUERY_FLAG(op, FLAG_REMOVED)) {
244  object_remove(op);
246  return;
247  }
248  }
249  }
250  } FOR_MAP_FINISH();
251 }
252 
253 /*****************************************************************************
254  *
255  * CONE RELATED FUNCTIONS
256  *
257  *****************************************************************************/
258 
265 void cone_drop(object *op) {
266  object *new_ob = arch_to_object(op->other_arch);
267 
268  new_ob->level = op->level;
270 
271  /* preserve skill ownership */
272  if (op->skill && op->skill != new_ob->skill) {
273  if (new_ob->skill)
274  free_string(new_ob->skill);
275  new_ob->skill = add_refcount(op->skill);
276  }
277  object_insert_in_map_at(new_ob, op->map, op, 0, op->x, op->y);
278 }
279 
297 int cast_cone(object *op, object *caster, int dir, object *spell) {
298  object *tmp;
299  int i, success = 0, range_min = -1, range_max = 1;
300  mapstruct *m;
301  int16_t sx, sy;
302  MoveType movetype;
303 
304  if (!spell->other_arch)
305  return 0;
306 
307  if (op->type == PLAYER && QUERY_FLAG(op, FLAG_UNDEAD) && op->attacktype&AT_TURN_UNDEAD) {
308  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR, "Your undead nature prevents you from turning undead!");
309  return 0;
310  }
311 
312  if (!dir) {
313  range_min = 0;
314  range_max = 8;
315  }
316 
317  /* Need to know what the movetype of the object we are about
318  * to create is, so we can know if the space we are about to
319  * insert it into is blocked.
320  */
321  movetype = spell->other_arch->clone.move_type;
322 
323  for (i = range_min; i <= range_max; i++) {
324  int16_t x, y, d;
325 
326  /* We can't use absdir here, because it never returns
327  * 0. If this is a rune, we want to hit the person on top
328  * of the trap (d==0). If it is not a rune, then we don't want
329  * to hit that person.
330  */
331  d = dir+i;
332  while (d < 0)
333  d += 8;
334  while (d > 8)
335  d -= 8;
336 
337  /* If it's not a rune, we don't want to blast the caster.
338  * In that case, we have to see - if dir is specified,
339  * turn this into direction 8. If dir is not specified (all
340  * direction) skip - otherwise, one line would do more damage
341  * because 0 direction will go through 9 directions - necessary
342  * for the rune code.
343  */
344  if (caster->type != RUNE && d == 0) {
345  if (dir != 0)
346  d = 8;
347  else
348  continue;
349  }
350 
351  x = op->x+freearr_x[d];
352  y = op->y+freearr_y[d];
353 
354  if (get_map_flags(op->map, &m, x, y, &sx, &sy)&P_OUT_OF_MAP)
355  continue;
356 
357  if ((movetype&GET_MAP_MOVE_BLOCK(m, sx, sy)) == movetype)
358  continue;
359 
360  success = 1;
361  tmp = arch_to_object(spell->other_arch);
363  set_spell_skill(op, caster, spell, tmp);
364  tmp->level = caster_level(caster, spell);
365  tmp->attacktype = spell->attacktype;
366 
367  /* holy word stuff */
368  if ((tmp->attacktype&AT_HOLYWORD) || (tmp->attacktype&AT_GODPOWER)) {
369  if (!tailor_god_spell(tmp, op))
370  return 0;
371  }
372 
373  if (dir)
374  tmp->stats.sp = dir;
375  else
376  tmp->stats.sp = i;
377 
378  tmp->range = spell->range+SP_level_range_adjust(caster, spell);
379 
380  /* If casting it in all directions, it doesn't go as far */
381  if (dir == 0) {
382  tmp->range /= 4;
383  if (tmp->range < 2 && spell->range >= 2)
384  tmp->range = 2;
385  }
386  tmp->stats.dam = spell->stats.dam+SP_level_dam_adjust(caster, spell);
387  tmp->duration = spell->duration+SP_level_duration_adjust(caster, spell);
388 
389  /* Special bonus for fear attacks */
390  if (tmp->attacktype&AT_FEAR) {
391  if (caster->type == PLAYER)
392  tmp->duration += get_fear_bonus(caster->stats.Cha);
393  else
394  tmp->duration += caster->level/3;
395  }
396  if (tmp->attacktype&(AT_HOLYWORD|AT_TURN_UNDEAD)) {
397  if (caster->type == PLAYER)
398  tmp->duration += get_turn_bonus(caster->stats.Wis)/5;
399  else
400  tmp->duration += caster->level/3;
401  }
402 
403  if (!(tmp->move_type&MOVE_FLY_LOW))
404  LOG(llevDebug, "cast_cone(): arch %s doesn't have flying 1\n", spell->other_arch->name);
405 
406  if (!tmp->move_on && tmp->stats.dam) {
407  LOG(llevDebug, "cast_cone(): arch %s doesn't have move_on set\n", spell->other_arch->name);
408  }
409 
410  /* This is used for tracking spells so that one effect doesn't hit
411  * a single space too many times.
412  */
413  tmp->stats.maxhp = tmp->count;
414  if (tmp->stats.maxhp == 0)
415  tmp->stats.maxhp = 1;
416 
417  object_insert_in_map_at(tmp, m, op, 0, sx, sy);
418 
419  if (tmp->other_arch)
420  cone_drop(tmp);
421  }
422  return success;
423 }
424 
425 /****************************************************************************
426  *
427  * BOMB related code
428  *
429  ****************************************************************************/
430 
447 int create_bomb(object *op, object *caster, int dir, object *spell) {
448  object *tmp;
449  int mflags;
450  int16_t dx = op->x+freearr_x[dir], dy = op->y+freearr_y[dir];
451  mapstruct *m;
452 
453  mflags = get_map_flags(op->map, &m, dx, dy, &dx, &dy);
454  if ((mflags&P_OUT_OF_MAP) || (GET_MAP_MOVE_BLOCK(m, dx, dy)&MOVE_WALK)) {
455  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR, "There is something in the way.");
456  return 0;
457  }
458  tmp = arch_to_object(spell->other_arch);
459 
460  /* level dependencies for bomb */
461  tmp->range = spell->range+SP_level_range_adjust(caster, spell);
462  tmp->stats.dam = spell->stats.dam+SP_level_dam_adjust(caster, spell);
463  tmp->duration = spell->duration+SP_level_duration_adjust(caster, spell);
464  tmp->attacktype = spell->attacktype;
465 
467  set_spell_skill(op, caster, spell, tmp);
468  object_insert_in_map_at(tmp, m, op, 0, dx, dy);
469  return 1;
470 }
471 
472 /****************************************************************************
473  *
474  * smite related spell code.
475  *
476  ****************************************************************************/
477 
496 static object *get_pointed_target(object *op, int dir, int range, int type) {
497  object *target;
498  int16_t x, y;
499  int dist, mflags;
500  mapstruct *mp;
501 
502  if (dir == 0)
503  return NULL;
504 
505  for (dist = 1; dist < range; dist++) {
506  x = op->x+freearr_x[dir]*dist;
507  y = op->y+freearr_y[dir]*dist;
508  mp = op->map;
509  mflags = get_map_flags(op->map, &mp, x, y, &x, &y);
510 
511  if (mflags&P_OUT_OF_MAP)
512  return NULL;
513  if ((type&SPELL_MANA) && (mflags&P_NO_MAGIC))
514  return NULL;
515  if ((type&SPELL_GRACE) && (mflags&P_NO_CLERIC))
516  return NULL;
518  return NULL;
519 
520  if (mflags&P_IS_ALIVE) {
521  target = map_find_by_flag(mp, x, y, FLAG_MONSTER);
522  if (target != NULL) {
523  return target;
524  }
525  }
526  }
527  return NULL;
528 }
529 
546 int cast_smite_spell(object *op, object *caster, int dir, object *spell) {
547  object *effect, *target;
548  const object *god = find_god(determine_god(op));
549  int range;
550 
551  range = spell->range+SP_level_range_adjust(caster, spell);
552  target = get_pointed_target(op, dir, range, spell->stats.grace ? SPELL_GRACE : SPELL_MANA);
553 
554  /* Bunch of conditions for casting this spell. Note that only
555  * require a god if this is a cleric spell (requires grace).
556  * This makes this spell much more general purpose - it can be used
557  * by wizards also, which is good, because I think this is a very
558  * interesting spell.
559  * if it is a cleric spell, you need a god, and the creature
560  * can't be friendly to your god.
561  */
562 
563  if (!target
564  || QUERY_FLAG(target, FLAG_REFL_SPELL)
565  || (!god && spell->stats.grace)
566  || (target->title && god && !strcmp(target->title, god->name))
567  || (target->race && god && strstr(target->race, god->race))) {
568  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE, "Your request is unheeded.");
569  return 0;
570  }
571 
572  if (spell->other_arch)
573  effect = arch_to_object(spell->other_arch);
574  else
575  return 0;
576 
577  /* tailor the effect by priest level and worshipped God */
578  effect->level = caster_level(caster, spell);
579  effect->attacktype = spell->attacktype;
580  if (effect->attacktype&(AT_HOLYWORD|AT_GODPOWER)) {
581  if (tailor_god_spell(effect, op))
583  "%s answers your call!",
584  determine_god(op));
585  else {
586  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE, "Your request is ignored.");
587  return 0;
588  }
589  }
590 
591  /* size of the area of destruction */
592  effect->range = spell->range+SP_level_range_adjust(caster, spell);
593  effect->duration = spell->duration+SP_level_range_adjust(caster, spell);
594 
595  if (effect->attacktype&AT_DEATH) {
596  effect->level = spell->stats.dam+SP_level_dam_adjust(caster, spell);
597 
598  /* casting death spells at undead isn't a good thing */
599  if (QUERY_FLAG(target, FLAG_UNDEAD)) {
600  if (random_roll(0, 2, op, PREFER_LOW)) {
601  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE, "Idiot! Your spell boomerangs!");
602  effect->x = op->x;
603  effect->y = op->y;
604  } else {
605  char target_name[HUGE_BUF];
606 
607  query_name(target, target_name, HUGE_BUF);
610  "The %s looks stronger!",
611  target_name);
612  target->stats.hp = target->stats.maxhp*2;
614  return 0;
615  }
616  }
617  } else {
618  /* how much woe to inflict :) */
619  effect->stats.dam = spell->stats.dam+SP_level_dam_adjust(caster, spell);
620  }
621 
622  if (effect->type == SPELL_EFFECT && effect->subtype == SP_EXPLOSION) {
623  /* Used for spell tracking - just need a unique val for this spell -
624  * the count of the parent should work fine.
625  *
626  * Without this the server can easily get overloaded at high level
627  * spells.
628  */
629  effect->stats.maxhp = spell->count;
630  if (effect->stats.maxhp == 0)
631  effect->stats.maxhp = 1;
632  }
633 
634  object_set_owner(effect, op);
635  set_spell_skill(op, caster, spell, effect);
636 
637  /* ok, tell it where to be, and insert! */
638  object_insert_in_map_at(effect, target->map, op, 0, target->x, target->y);
639 
640  return 1;
641 }
642 
643 /****************************************************************************
644  * Destruction
645  ****************************************************************************/
646 
665 static int make_object_glow(object *op, int radius, int time) {
666  object *tmp;
667 
668  /* some things are unaffected... */
669  if (op->path_denied&PATH_LIGHT)
670  return 0;
671 
673  tmp->speed = 0.01;
674  tmp->stats.food = time;
676  tmp->glow_radius = radius;
677  if (tmp->glow_radius > MAX_LIGHT_RADII)
678  tmp->glow_radius = MAX_LIGHT_RADII;
679 
680  tmp->x = op->x;
681  tmp->y = op->y;
682  if (tmp->speed < MIN_ACTIVE_SPEED)
683  tmp->speed = MIN_ACTIVE_SPEED; /* safety */
685  if (tmp->glow_radius > op->glow_radius)
686  op->glow_radius = tmp->glow_radius;
687 
688  if (!tmp->env || op != tmp->env) {
689  LOG(llevError, "make_object_glow() failed to insert glowing force in %s\n", op->name);
690  return 0;
691  }
692  return 1;
693 }
694 
707 int cast_destruction(object *op, object *caster, object *spell_ob) {
708  int i, j, range, mflags, friendly = 0, dam, dur;
709  int16_t sx, sy;
710  mapstruct *m;
711  object *tmp, *found_skill;
712  const char *skill;
713 
714  range = spell_ob->range+SP_level_range_adjust(caster, spell_ob);
715  dam = spell_ob->stats.dam+SP_level_dam_adjust(caster, spell_ob);
716  dur = spell_ob->duration+SP_level_duration_adjust(caster, spell_ob);
717  if (QUERY_FLAG(op, FLAG_FRIENDLY) || op->type == PLAYER)
718  friendly = 1;
719 
720  /* destruction doesn't use another spell object, so we need
721  * update op's skill pointer so that exp is properly awarded.
722  * We do some shortcuts here - since this is just temporary
723  * and we'll reset the values back, we don't need to go through
724  * the full share string/free_string route.
725  */
726  skill = op->skill;
727  if (caster == op)
728  op->skill = spell_ob->skill;
729  else if (caster->skill)
730  op->skill = caster->skill;
731  else
732  op->skill = NULL;
733 
734  /* The skill may be NULL (if op is not a player but eg a bulletwall), but that's ok because change_skill does what is right. */
735  found_skill = find_skill_by_name(op, op->skill);
736  change_skill(op, found_skill, 1);
737 
738  for (i = -range; i < range; i++) {
739  for (j = -range; j < range; j++) {
740  m = op->map;
741  sx = op->x+i;
742  sy = op->y+j;
743  mflags = get_map_flags(m, &m, sx, sy, &sx, &sy);
744  if (mflags&P_OUT_OF_MAP)
745  continue;
746  if (mflags&P_IS_ALIVE) {
747  tmp = NULL;
748  FOR_MAP_PREPARE(m, sx, sy, inv) {
749  tmp = inv;
750  if (QUERY_FLAG(tmp, FLAG_ALIVE) || tmp->type == PLAYER)
751  break;
752  } FOR_MAP_FINISH();
753  if (tmp) {
754  tmp = HEAD(tmp);
755  if ((friendly && !QUERY_FLAG(tmp, FLAG_FRIENDLY) && tmp->type != PLAYER)
756  || (!friendly && (QUERY_FLAG(tmp, FLAG_FRIENDLY) || tmp->type == PLAYER))) {
757  if (spell_ob->subtype == SP_DESTRUCTION) {
758  hit_player(tmp, dam, op, spell_ob->attacktype, 0);
759  if (spell_ob->other_arch) {
760  tmp = arch_to_object(spell_ob->other_arch);
761  object_insert_in_map_at(tmp, m, op, 0, sx, sy);
762  }
763  } else if (spell_ob->subtype == SP_FAERY_FIRE && tmp->resist[ATNR_MAGIC] != 100) {
764  if (make_object_glow(tmp, 1, dur) && spell_ob->other_arch) {
765  object *effect = arch_to_object(spell_ob->other_arch);
766  object_insert_in_map_at(effect, m, op, 0, sx, sy);
767  }
768  }
769  }
770  }
771  }
772  }
773  }
774  op->skill = skill;
775  return 1;
776 }
777 
778 /***************************************************************************
779  *
780  * CURSE
781  *
782  ***************************************************************************/
783 
800 int cast_curse(object *op, object *caster, object *spell_ob, int dir) {
801  const object *god = find_god(determine_god(op));
802  object *tmp, *force;
803 
804  tmp = get_pointed_target(op, (dir == 0) ? op->direction : dir, spell_ob->range, SPELL_GRACE);
805  if (!tmp) {
806  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE, "There is no one in that direction to curse.");
807  return 0;
808  }
809 
810  /* If we've already got a force of this type, don't add a new one. */
811  force = NULL;
813  if (inv->type == FORCE && inv->subtype == FORCE_CHANGE_ABILITY) {
814  if (inv->name == spell_ob->name) {
815  force = inv;
816  break;
817  } else if (spell_ob->race && spell_ob->race == inv->name) {
820  "You can not cast %s while %s is in effect",
821  spell_ob->name, force->name_pl);
822  return 0;
823  }
824  }
825  } FOR_INV_FINISH();
826 
827  if (force == NULL) {
829  force->subtype = FORCE_CHANGE_ABILITY;
830  free_string(force->name);
831  if (spell_ob->race)
832  force->name = add_refcount(spell_ob->race);
833  else
834  force->name = add_refcount(spell_ob->name);
835  free_string(force->name_pl);
836  force->name_pl = add_refcount(spell_ob->name);
837  } else {
838  int duration;
839 
840  duration = spell_ob->duration+SP_level_duration_adjust(caster, spell_ob)*50;
841  if (duration > force->duration) {
842  force->duration = duration;
843  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_SUCCESS, "You recast the spell while in effect.");
844  } else {
845  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE, "Recasting the spell had no effect.");
846  }
847  return 1;
848  }
849  force->duration = spell_ob->duration+SP_level_duration_adjust(caster, spell_ob)*50;
850  force->speed = 1.0;
851  force->speed_left = -1.0;
853 
854  if (god) {
855  if (spell_ob->last_grace)
856  force->path_repelled = god->path_repelled;
857  if (spell_ob->last_grace)
858  force->path_denied = god->path_denied;
860  "You are a victim of %s's curse!",
861  god->name);
862  } else
863  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE, "Your curse seems empty.");
864 
865 
866  if (tmp != op && op->type == PLAYER)
868  "You curse %s!",
869  tmp->name);
870 
871  force->stats.ac = spell_ob->stats.ac;
872  force->stats.wc = spell_ob->stats.wc;
873 
874  change_abil(tmp, force); /* Mostly to display any messages */
876  fix_object(tmp);
877 
878  if (spell_ob->other_arch != NULL && tmp->map != NULL) {
879  object_insert_in_map_at(arch_to_object(spell_ob->other_arch), tmp->map, NULL, INS_ON_TOP, tmp->x, tmp->y);
880  }
881 
882  return 1;
883 }
884 
885 /**********************************************************************
886  * mood change
887  * Arguably, this may or may not be an attack spell. But since it
888  * effects monsters, it seems best to put it into this file
889  ***********************************************************************/
890 
904 int mood_change(object *op, object *caster, object *spell) {
905  object *tmp, *head;
906  const object *god;
907  int done_one, range, mflags, level, at, best_at, immunity_chance = 50;
908  int16_t x, y, nx, ny;
909  mapstruct *m;
910  const char *race;
911 
912  /* We pre-compute some values here so that we don't have to keep
913  * doing it over and over again.
914  */
915  god = find_god(determine_god(op));
916  level = caster_level(caster, spell);
917  range = spell->range+SP_level_range_adjust(caster, spell);
918  race = object_get_value(spell, "immunity_chance");
919  if (race != NULL) {
920  immunity_chance = atoi(race);
921  if (immunity_chance < 0 || immunity_chance > 100) {
922  LOG(llevError, "ignoring invalid immunity_chance %d for %s\n", immunity_chance, spell->arch->name);
923  immunity_chance = 50;
924  }
925  }
926 
927  /* On the bright side, no monster should ever have a race of GOD_...
928  * so even if the player doesn't worship a god, if race=GOD_.., it
929  * won't ever match anything.
930  */
931  if (!spell->race)
932  race = NULL;
933  else if (god && !strcmp(spell->race, "GOD_SLAYING"))
934  race = god->slaying;
935  else if (god && !strcmp(spell->race, "GOD_FRIEND"))
936  race = god->race;
937  else
938  race = spell->race;
939 
940  for (x = op->x-range; x <= op->x+range; x++)
941  for (y = op->y-range; y <= op->y+range; y++) {
942  done_one = 0;
943  m = op->map;
944  mflags = get_map_flags(m, &m, x, y, &nx, &ny);
945  if (mflags&P_OUT_OF_MAP)
946  continue;
947 
948  /* If there is nothing living on this space, no need to go further */
949  if (!(mflags&P_IS_ALIVE))
950  continue;
951 
952  head = map_find_by_flag(m, nx, ny, FLAG_MONSTER);
953  /* There can be living objects that are not monsters */
954  if (!head || head->type == PLAYER)
955  continue;
956 
957  /* Make sure the race is OK. Likewise, only effect undead if spell specifically allows it */
958  if (race && head->race && !strstr(race, head->race))
959  continue;
960  if (QUERY_FLAG(head, FLAG_UNDEAD) && !QUERY_FLAG(spell, FLAG_UNDEAD))
961  continue;
962 
963  /* Now do a bunch of stuff related to saving throws */
964  best_at = -1;
965  if (spell->attacktype) {
966  for (at = 0; at < NROFATTACKS; at++)
967  if (spell->attacktype&(1<<at))
968  if (best_at == -1 || head->resist[at] > head->resist[best_at])
969  best_at = at;
970 
971  if (best_at == -1)
972  at = 0;
973  else {
974  if (head->resist[best_at] == 100)
975  continue;
976  else
977  at = head->resist[best_at]/5;
978  }
979  at -= level/5;
980  if (did_make_save(head, head->level, at))
981  continue;
982  } else { /* spell->attacktype */
983  /*
984  * Spell has no attacktype (charm&such), so we'll have a specific saving:
985  * if spell level < monster level, no go
986  * else, chance of effect = 20+min(50, 2*(spell level-monster level))
987  *
988  * The chance will then be in the range [20-70] percent, not too bad.
989  *
990  * This is required to fix the 'charm monster' abuse, where a player level 1 can
991  * charm a level 125 monster...
992  *
993  * Ryo, august 14th
994  */
995  if (head->level > level)
996  continue;
997  if (random_roll(0, 100, caster, PREFER_LOW) >= (20+MIN(50, 2*(level-head->level)))) {
998  /* Additionnally, randomly make the monster immune to that spell. */
999  if (random_roll(0, 100, caster, PREFER_HIGH) <= immunity_chance) {
1000  object_set_value(head, "no_mood_change", "1", 1);
1001  }
1002  continue;
1003  }
1004 
1005  /*
1006  * There was no way to ensure immunity, so added a key/value for that.
1007  * Nicolas, september 2010.
1008  */
1009  if (object_value_set(head, "no_mood_change"))
1010  continue;
1011  }
1012 
1013  /* Done with saving throw. Now start effecting the monster */
1014 
1015  /* aggravation */
1016  if (QUERY_FLAG(spell, FLAG_MONSTER)) {
1017  CLEAR_FLAG(head, FLAG_SLEEP);
1018  // Make sure unaggressive monsters also go to attack
1020  if (QUERY_FLAG(head, FLAG_FRIENDLY))
1021  remove_friendly_object(head);
1022 
1023  done_one = 1;
1024  // Prevent three-player abuse w/ two casting aggravation at a distance and the last punishing the
1025  // monsters who can't decide who to attack.
1026  // Also prevents aggravation -> singing -> aggravation loops
1027  object_set_value(head, "no_mood_change", "1", 1);
1028  // They big mad
1029  object_set_enemy(head, op);
1030  }
1031 
1032  /* calm monsters */
1033  if (QUERY_FLAG(spell, FLAG_UNAGGRESSIVE) && !QUERY_FLAG(head, FLAG_UNAGGRESSIVE)) {
1034  SET_FLAG(head, FLAG_UNAGGRESSIVE);
1035  object_set_enemy(head, NULL);
1036  done_one = 1;
1037  }
1038 
1039  /* berserk monsters */
1040  if (QUERY_FLAG(spell, FLAG_BERSERK) && !QUERY_FLAG(head, FLAG_BERSERK)) {
1041  SET_FLAG(head, FLAG_BERSERK);
1042  done_one = 1;
1043  }
1044  /* charm */
1045  if (QUERY_FLAG(spell, FLAG_NO_ATTACK) && !QUERY_FLAG(head, FLAG_FRIENDLY)) {
1046  SET_FLAG(head, FLAG_FRIENDLY);
1047  /* Prevent uncontrolled outbreaks of self replicating monsters.
1048  Typical use case is charm, go somewhere, use aggravation to make hostile.
1049  This could lead to fun stuff like mice outbreak in bigworld and server crawl. */
1050  CLEAR_FLAG(head, FLAG_GENERATOR);
1051  object_set_owner(head, op);
1052  set_spell_skill(op, caster, spell, head);
1053  add_friendly_object(head);
1054  head->attack_movement = PETMOVE;
1055  done_one = 1;
1056  share_exp(op, head->stats.exp/2, head->skill, SK_EXP_ADD_SKILL);
1057  head->stats.exp = 0;
1058  }
1059 
1060  /* If a monster was affected, put an effect in */
1061  if (done_one && spell->other_arch) {
1062  tmp = arch_to_object(spell->other_arch);
1063  object_insert_in_map_at(tmp, m, op, 0, nx, ny);
1064  }
1065  } /* for y */
1066 
1067  return 1;
1068 }
1069 
1070 
1088 int fire_swarm(object *op, object *caster, object *spell, int dir) {
1089  object *tmp;
1090  int i;
1091 
1092  if (!spell->other_arch)
1093  return 0;
1094 
1096  object_set_owner(tmp, op); /* needed so that if swarm elements kill, caster gets xp.*/
1097  set_spell_skill(op, caster, spell, tmp);
1098 
1099  tmp->level = caster_level(caster, spell); /*needed later, to get level dep. right.*/
1100  tmp->spell = arch_to_object(spell->other_arch);
1101 
1102  tmp->attacktype = tmp->spell->attacktype;
1103 
1104  if (tmp->attacktype&AT_HOLYWORD || tmp->attacktype&AT_GODPOWER) {
1105  if (!tailor_god_spell(tmp, op))
1106  return 1;
1107  }
1108  tmp->duration = SP_level_duration_adjust(caster, spell);
1109  for (i = 0; i < spell->duration; i++)
1110  tmp->duration += die_roll(1, 3, op, PREFER_HIGH);
1111 
1112  tmp->direction = dir;
1113  tmp->invisible = 1;
1114  object_insert_in_map_at(tmp, op->map, op, 0, op->x, op->y);
1115  return 1;
1116 }
1117 
1136 int cast_light(object *op, object *caster, object *spell, int dir) {
1137  object *target = NULL, *tmp = NULL;
1138  int16_t x, y;
1139  int dam, mflags;
1140  mapstruct *m;
1141 
1142  dam = spell->stats.dam+SP_level_dam_adjust(caster, spell);
1143 
1144  if (!dir) {
1145  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR, "In what direction?");
1146  return 0;
1147  }
1148 
1149  x = op->x+freearr_x[dir];
1150  y = op->y+freearr_y[dir];
1151  m = op->map;
1152 
1153  mflags = get_map_flags(m, &m, x, y, &x, &y);
1154 
1155  if (mflags&P_OUT_OF_MAP) {
1156  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE, "Nothing is there.");
1157  return 0;
1158  }
1159 
1160  if (mflags&P_IS_ALIVE && spell->attacktype) {
1161  target = map_find_by_flag(m, x, y, FLAG_MONSTER);
1162  if (target != NULL) {
1163  /* oky doky. got a target monster. Lets make a blinding attack */
1164  (void)hit_player(target, dam, op, spell->attacktype, 1);
1165  return 1; /* one success only! */
1166  }
1167  }
1168 
1169  /* no live target, perhaps a wall is in the way? */
1171  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_ERROR, "Something is in the way.");
1172  return 0;
1173  }
1174 
1175  /* ok, looks groovy to just insert a new light on the map */
1176  tmp = arch_to_object(spell->other_arch);
1177  if (!tmp) {
1178  LOG(llevError, "Error: spell arch for cast_light() missing.\n");
1179  return 0;
1180  }
1181  tmp->stats.food = spell->duration+SP_level_duration_adjust(caster, spell);
1182  if (tmp->glow_radius) {
1183  tmp->glow_radius = spell->range+SP_level_range_adjust(caster, spell);
1184  if (tmp->glow_radius > MAX_LIGHT_RADII)
1185  tmp->glow_radius = MAX_LIGHT_RADII;
1186  }
1187  object_insert_in_map_at(tmp, m, op, 0, x, y);
1188  return 1;
1189 }
1190 
1207 int cast_cause_disease(object *op, object *caster, object *spell, int dir) {
1208  int16_t x, y;
1209  int i, mflags, range, dam_mod, dur_mod;
1210  object *target_head;
1211  mapstruct *m;
1212 
1213  x = op->x;
1214  y = op->y;
1215 
1216  /* If casting from a scroll, no direction will be available, so refer to the
1217  * direction the player is pointing.
1218  */
1219  if (!dir)
1220  dir = op->facing;
1221  if (!dir)
1222  return 0; /* won't find anything if casting on ourself, so just return */
1223 
1224  /* Calculate these once here */
1225  range = spell->range+SP_level_range_adjust(caster, spell);
1226  dam_mod = SP_level_dam_adjust(caster, spell);
1227  dur_mod = SP_level_duration_adjust(caster, spell);
1228 
1229  /* search in a line for a victim */
1230  for (i = 1; i < range; i++) {
1231  x = op->x+i*freearr_x[dir];
1232  y = op->y+i*freearr_y[dir];
1233  m = op->map;
1234 
1235  mflags = get_map_flags(m, &m, x, y, &x, &y);
1236 
1237  if (mflags&P_OUT_OF_MAP)
1238  return 0;
1239 
1240  /* don't go through walls - presume diseases are airborne */
1242  return 0;
1243 
1244  /* Only bother looking on this space if there is something living here */
1245  if (mflags&P_IS_ALIVE) {
1246  /* search this square for a victim */
1247  FOR_MAP_PREPARE(m, x, y, walk) {
1248  /* Flags for monster is set on head only, so get it now */
1249  target_head = HEAD(walk);
1250  if (QUERY_FLAG(target_head, FLAG_MONSTER) || (target_head->type == PLAYER)) { /* found a victim */
1251  object *disease = arch_to_object(spell->other_arch);
1252 
1253  object_set_owner(disease, op);
1254  set_spell_skill(op, caster, spell, disease);
1255  disease->stats.exp = 0;
1256  disease->level = caster_level(caster, spell);
1257 
1258  /* do level adjustments */
1259  if (disease->stats.wc)
1260  disease->stats.wc += dur_mod/2;
1261 
1262  if (disease->magic > 0)
1263  disease->magic += dur_mod/4;
1264 
1265  if (disease->stats.maxhp > 0)
1266  disease->stats.maxhp += dur_mod;
1267 
1268  if (disease->stats.maxgrace > 0)
1269  disease->stats.maxgrace += dur_mod;
1270 
1271  if (disease->stats.dam) {
1272  if (disease->stats.dam > 0)
1273  disease->stats.dam += dam_mod;
1274  else
1275  disease->stats.dam -= dam_mod;
1276  }
1277 
1278  if (disease->last_sp) {
1279  disease->last_sp -= 2*dam_mod;
1280  if (disease->last_sp < 1)
1281  disease->last_sp = 1;
1282  }
1283 
1284  if (disease->stats.maxsp) {
1285  if (disease->stats.maxsp > 0)
1286  disease->stats.maxsp += dam_mod;
1287  else
1288  disease->stats.maxsp -= dam_mod;
1289  }
1290 
1291  if (disease->stats.ac)
1292  disease->stats.ac += dam_mod;
1293 
1294  if (disease->last_eat)
1295  disease->last_eat -= dam_mod;
1296 
1297  if (disease->stats.hp)
1298  disease->stats.hp -= dam_mod;
1299 
1300  if (disease->stats.sp)
1301  disease->stats.sp -= dam_mod;
1302 
1303  if (infect_object(target_head, disease, 1)) {
1304  object *flash; /* visual effect for inflicting disease */
1305 
1306  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_SUCCESS, "You inflict %s on %s!", disease->name, target_head->name);
1307 
1308  object_free_drop_inventory(disease); /* don't need this one anymore */
1310  object_insert_in_map_at(flash, walk->map, op, 0, x, y);
1311  return 1;
1312  }
1313  object_free_drop_inventory(disease);
1314  } /* Found a victim */
1315  } FOR_MAP_FINISH(); /* Search squares for living creature */
1316  } /* if living creature on square */
1317  } /* for range of spaces */
1318  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_SPELL, MSG_TYPE_SPELL_FAILURE, "No one caught anything!");
1319  return 1;
1320 }
SP_level_range_adjust
int SP_level_range_adjust(const object *caster, const object *spob)
Definition: spell_util.c:337
object_was_destroyed
#define object_was_destroyed(op, old_tag)
Definition: object.h:68
FORCE_CHANGE_ABILITY
#define FORCE_CHANGE_ABILITY
Definition: spells.h:145
PLAYER
@ PLAYER
Definition: object.h:107
obj::attack_movement
uint16_t attack_movement
Definition: object.h:396
set_spell_skill
void set_spell_skill(object *op, object *caster, object *spob, object *dest)
Definition: spell_util.c:92
global.h
add_refcount
sstring add_refcount(sstring str)
Definition: shstr.c:210
liv::dam
int16_t dam
Definition: living.h:46
INS_NO_WALK_ON
#define INS_NO_WALK_ON
Definition: object.h:568
object_remove
void object_remove(object *op)
Definition: object.c:1819
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Definition: define.h:730
remove_friendly_object
void remove_friendly_object(object *op)
Definition: friend.cpp:56
object_set_enemy
void object_set_enemy(object *op, object *enemy)
Definition: object.c:919
AT_MAGIC
#define AT_MAGIC
Definition: attack.h:77
PATH_LIGHT
#define PATH_LIGHT
Definition: spells.h:32
llevError
@ llevError
Definition: logger.h:11
SP_BOMB
#define SP_BOMB
Definition: spells.h:82
object_copy_owner
void object_copy_owner(object *op, object *clone)
Definition: object.c:897
FLAG_UNDEAD
#define FLAG_UNDEAD
Definition: define.h:270
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
FLAG_GENERATOR
#define FLAG_GENERATOR
Definition: define.h:248
diamondslots.x
x
Definition: diamondslots.py:15
obj::count
tag_t count
Definition: object.h:302
SP_FAERY_FIRE
#define SP_FAERY_FIRE
Definition: spells.h:118
obj::map
struct mapdef * map
Definition: object.h:300
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
obj::race
sstring race
Definition: object.h:321
liv::maxgrace
int16_t maxgrace
Definition: living.h:45
liv::wc
int8_t wc
Definition: living.h:37
out_of_map
int out_of_map(mapstruct *m, int x, int y)
Definition: map.c:2312
get_fear_bonus
int get_fear_bonus(int stat)
Definition: living.c:2386
liv::maxhp
int16_t maxhp
Definition: living.h:41
tailor_god_spell
int tailor_god_spell(object *spellop, object *caster)
Definition: gods.c:1222
get_turn_bonus
int get_turn_bonus(int stat)
Definition: living.c:2374
share_exp
void share_exp(object *op, int64_t exp, const char *skill, int flag)
Definition: living.c:2312
PREFER_LOW
#define PREFER_LOW
Definition: define.h:564
infect_object
int infect_object(object *victim, object *disease, int force)
Definition: disease.c:317
MoveType
unsigned char MoveType
Definition: define.h:417
liv::hp
int16_t hp
Definition: living.h:40
SP_CONE
#define SP_CONE
Definition: spells.h:81
commongive.inv
inv
Definition: commongive.py:28
MIN
#define MIN(x, y)
Definition: compat.h:21
MSG_TYPE_VICTIM_SPELL
#define MSG_TYPE_VICTIM_SPELL
Definition: newclient.h:654
SP_level_duration_adjust
int SP_level_duration_adjust(const object *caster, const object *spob)
Definition: spell_util.c:311
RUNE
@ RUNE
Definition: object.h:240
change_skill
int change_skill(object *who, object *new_skill, int flag)
Definition: skill_util.c:350
obj::path_denied
uint32_t path_denied
Definition: object.h:350
DIRX
#define DIRX(xyz)
Definition: define.h:463
Ice.tmp
int tmp
Definition: Ice.py:207
cast_curse
int cast_curse(object *op, object *caster, object *spell_ob, int dir)
Definition: spell_attack.c:800
hit_map
int hit_map(object *op, int dir, uint32_t type, int full_hit)
Definition: attack.c:349
P_NO_MAGIC
#define P_NO_MAGIC
Definition: map.h:228
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
P_IS_ALIVE
#define P_IS_ALIVE
Definition: map.h:238
FLAG_APPLIED
#define FLAG_APPLIED
Definition: define.h:235
HUGE_BUF
#define HUGE_BUF
Definition: define.h:37
MSG_TYPE_VICTIM
#define MSG_TYPE_VICTIM
Definition: newclient.h:415
ob_process
method_ret ob_process(object *op)
Definition: ob_methods.c:67
mood_change
int mood_change(object *op, object *caster, object *spell)
Definition: spell_attack.c:904
make_object_glow
static int make_object_glow(object *op, int radius, int time)
Definition: spell_attack.c:665
freearr_x
short freearr_x[SIZEOFFREE]
Definition: object.c:299
AT_DEATH
#define AT_DEATH
Definition: attack.h:93
freearr_y
short freearr_y[SIZEOFFREE]
Definition: object.c:305
obj::duration
int16_t duration
Definition: object.h:408
find_god
const object * find_god(const char *name)
Definition: holy.cpp:321
FLAG_ALIVE
#define FLAG_ALIVE
Definition: define.h:230
get_pointed_target
static object * get_pointed_target(object *op, int dir, int range, int type)
Definition: spell_attack.c:496
MSG_TYPE_SPELL_SUCCESS
#define MSG_TYPE_SPELL_SUCCESS
Definition: newclient.h:635
object_get_value
const char * object_get_value(const object *op, const char *const key)
Definition: object.c:4317
obj::slaying
sstring slaying
Definition: object.h:322
free_string
void free_string(sstring str)
Definition: shstr.c:280
m
static event_registration m
Definition: citylife.cpp:427
liv::maxsp
int16_t maxsp
Definition: living.h:43
FLAG_NO_ATTACK
#define FLAG_NO_ATTACK
Definition: define.h:355
liv::exp
int64_t exp
Definition: living.h:47
PREFER_HIGH
#define PREFER_HIGH
Definition: define.h:563
obj::name
sstring name
Definition: object.h:314
determine_god
const char * determine_god(object *op)
Definition: gods.c:55
ARCH_DETECT_MAGIC
#define ARCH_DETECT_MAGIC
Definition: object.h:575
cast_cone
int cast_cone(object *op, object *caster, int dir, object *spell)
Definition: spell_attack.c:297
query_name
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:585
object_update_turn_face
void object_update_turn_face(object *op)
Definition: object.c:1313
MOVE_WALK
#define MOVE_WALK
Definition: define.h:392
obj::path_repelled
uint32_t path_repelled
Definition: object.h:349
liv::Cha
int8_t Cha
Definition: living.h:36
HEAD
#define HEAD(op)
Definition: object.h:593
SPELL_GRACE
#define SPELL_GRACE
Definition: spells.h:59
absdir
int absdir(int d)
Definition: object.c:3685
obj::x
int16_t x
Definition: object.h:330
INS_NO_MERGE
#define INS_NO_MERGE
Definition: object.h:566
fix_object
void fix_object(object *op)
Definition: living.c:1126
map_find_by_flag
object * map_find_by_flag(mapstruct *map, int x, int y, int flag)
Definition: map.c:2680
GET_MAP_MOVE_BLOCK
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Definition: map.h:193
obj::other_arch
struct archt * other_arch
Definition: object.h:418
FOR_INV_FINISH
#define FOR_INV_FINISH()
Definition: define.h:677
object_set_value
int object_set_value(object *op, const char *key, const char *value, int add_key)
Definition: object.c:4470
caster_level
int caster_level(const object *caster, const object *spell)
Definition: spell_util.c:193
FLAG_UNAGGRESSIVE
#define FLAG_UNAGGRESSIVE
Definition: define.h:272
tag_t
uint32_t tag_t
Definition: object.h:12
liv::Con
int8_t Con
Definition: living.h:36
sproto.h
cone_drop
void cone_drop(object *op)
Definition: spell_attack.c:265
mapdef
Definition: map.h:317
MSG_TYPE_SPELL
#define MSG_TYPE_SPELL
Definition: newclient.h:411
create_bomb
int create_bomb(object *op, object *caster, int dir, object *spell)
Definition: spell_attack.c:447
nlohmann::detail::void
j template void())
Definition: json.hpp:4099
SP_DESTRUCTION
#define SP_DESTRUCTION
Definition: spells.h:90
FLAG_MONSTER
#define FLAG_MONSTER
Definition: define.h:245
object_set_owner
void object_set_owner(object *op, object *owner)
Definition: object.c:844
find_skill_by_name
object * find_skill_by_name(object *who, const char *name)
Definition: skill_util.c:202
P_OUT_OF_MAP
#define P_OUT_OF_MAP
Definition: map.h:250
env
static std::shared_ptr< inja::Environment > env
Definition: mapper.cpp:2216
cast_smite_spell
int cast_smite_spell(object *op, object *caster, int dir, object *spell)
Definition: spell_attack.c:546
INS_ON_TOP
#define INS_ON_TOP
Definition: object.h:569
create_archetype
object * create_archetype(const char *name)
Definition: arch.cpp:281
fire_bolt
int fire_bolt(object *op, object *caster, int dir, object *spob)
Definition: spell_attack.c:61
FREE_AND_CLEAR_STR
#define FREE_AND_CLEAR_STR(xyz)
Definition: global.h:195
MOVE_FLY_LOW
#define MOVE_FLY_LOW
Definition: define.h:393
random_roll
int random_roll(int min, int max, const object *op, int goodbad)
Definition: utils.c:42
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:723
obj::y
int16_t y
Definition: object.h:330
obj::title
sstring title
Definition: object.h:320
obj::arch
struct archt * arch
Definition: object.h:417
sounds.h
FLAG_REMOVED
#define FLAG_REMOVED
Definition: define.h:232
cast_destruction
int cast_destruction(object *op, object *caster, object *spell_ob)
Definition: spell_attack.c:707
FLAG_REFL_SPELL
#define FLAG_REFL_SPELL
Definition: define.h:275
obj::type
uint8_t type
Definition: object.h:343
obj::last_grace
int16_t last_grace
Definition: object.h:364
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:262
FLAG_FRIENDLY
#define FLAG_FRIENDLY
Definition: define.h:246
spells.h
die_roll
int die_roll(int num, int size, const object *op, int goodbad)
Definition: utils.c:122
cast_cause_disease
int cast_cause_disease(object *op, object *caster, object *spell, int dir)
Definition: spell_attack.c:1207
obj::stats
living stats
Definition: object.h:373
SP_level_dam_adjust
int SP_level_dam_adjust(const object *caster, const object *spob)
Definition: spell_util.c:286
archt::clone
object clone
Definition: object.h:473
MSG_TYPE_SPELL_FAILURE
#define MSG_TYPE_SPELL_FAILURE
Definition: newclient.h:633
add_friendly_object
void add_friendly_object(object *op)
Definition: friend.cpp:36
AT_TURN_UNDEAD
#define AT_TURN_UNDEAD
Definition: attack.h:89
liv::Dex
int8_t Dex
Definition: living.h:36
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
did_make_save
int did_make_save(const object *op, int level, int bonus)
Definition: living.c:2282
liv::Wis
int8_t Wis
Definition: living.h:36
liv::grace
int16_t grace
Definition: living.h:44
give.op
op
Definition: give.py:33
object_value_set
bool object_value_set(const object *op, const char *const key)
Definition: object.c:4347
MSG_TYPE_SPELL_ERROR
#define MSG_TYPE_SPELL_ERROR
Definition: newclient.h:636
FLAG_REFLECTING
#define FLAG_REFLECTING
Definition: define.h:262
SPELL_EFFECT
@ SPELL_EFFECT
Definition: object.h:215
ATNR_MAGIC
#define ATNR_MAGIC
Definition: attack.h:50
obj::last_sp
int32_t last_sp
Definition: object.h:363
hit_player
int hit_player(object *op, int dam, object *hitter, uint32_t type, int full_hit)
Definition: attack.c:1860
diamondslots.y
y
Definition: diamondslots.py:16
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
Definition: object.c:2833
obj::subtype
uint8_t subtype
Definition: object.h:344
explode_bullet
void explode_bullet(object *op)
Definition: spell_attack.c:121
object_get_env_recursive
object * object_get_env_recursive(object *op)
Definition: object.c:594
obj::last_eat
int32_t last_eat
Definition: object.h:361
obj::move_type
MoveType move_type
Definition: object.h:429
arch_to_object
object * arch_to_object(archetype *at)
Definition: arch.cpp:232
fire_swarm
int fire_swarm(object *op, object *caster, object *spell, int dir)
Definition: spell_attack.c:1088
MIN_ACTIVE_SPEED
#define MIN_ACTIVE_SPEED
Definition: define.h:639
FLAG_IS_USED_UP
#define FLAG_IS_USED_UP
Definition: define.h:260
liv::ac
int8_t ac
Definition: living.h:38
obj::skill
sstring skill
Definition: object.h:324
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.c:2080
draw_ext_info
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: main.c:309
FLAG_BERSERK
#define FLAG_BERSERK
Definition: define.h:352
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.c:1546
AT_FEAR
#define AT_FEAR
Definition: attack.h:90
AT_GODPOWER
#define AT_GODPOWER
Definition: attack.h:96
SWARM_SPELL
#define SWARM_SPELL
Definition: spells.h:166
check_bullet
void check_bullet(object *op)
Definition: spell_attack.c:217
OB_TYPE_MOVE_BLOCK
#define OB_TYPE_MOVE_BLOCK(ob1, type)
Definition: define.h:432
level
int level
Definition: readable.c:1608
P_NO_CLERIC
#define P_NO_CLERIC
Definition: map.h:239
archt::name
sstring name
Definition: object.h:470
SK_EXP_ADD_SKILL
#define SK_EXP_ADD_SKILL
Definition: skills.h:78
PETMOVE
#define PETMOVE
Definition: define.h:501
obj::attacktype
uint32_t attacktype
Definition: object.h:347
AT_HOLYWORD
#define AT_HOLYWORD
Definition: attack.h:97
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.c:301
change_abil
int change_abil(object *op, object *tmp)
Definition: living.c:395
liv::sp
int16_t sp
Definition: living.h:42
living.h
SP_EXPLOSION
#define SP_EXPLOSION
Definition: spells.h:80
obj::magic
int8_t magic
Definition: object.h:353
obj::resist
int16_t resist[NROFATTACKS]
Definition: object.h:346
FLAG_SLEEP
#define FLAG_SLEEP
Definition: define.h:307
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:670
FORCE
@ FORCE
Definition: object.h:224
cast_light
int cast_light(object *op, object *caster, object *spell, int dir)
Definition: spell_attack.c:1136
MAX_LIGHT_RADII
#define MAX_LIGHT_RADII
Definition: define.h:450
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Definition: main.c:319
object.h
obj::level
int16_t level
Definition: object.h:356
llevDebug
@ llevDebug
Definition: logger.h:13
obj::range
int8_t range
Definition: object.h:410
DIRY
#define DIRY(xyz)
Definition: define.h:464
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
FORCE_NAME
#define FORCE_NAME
Definition: spells.h:169
SPELL_MANA
#define SPELL_MANA
Definition: spells.h:58
dragon_attune.force
force
Definition: dragon_attune.py:45
object_get_owner
object * object_get_owner(object *op)
Definition: object.c:808
level
Definition: level.py:1