Crossfire Server, Trunk  1.75.0
spell_attack.cpp
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 
85  object_set_owner(tmp, op);
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))) {
94  if (!QUERY_FLAG(tmp, FLAG_REFLECTING)) {
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 
160  object_copy_owner(tmp, op);
161  if (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 */
230  explode_bullet(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;
269  object_set_owner(new_ob, object_get_owner(op));
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);
362  object_set_owner(tmp, op);
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  }
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 
466  object_set_owner(tmp, op);
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;
517  if (GET_MAP_MOVE_BLOCK(mp, x, y)&MOVE_FLY_LOW)
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)
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 */
684  tmp = object_insert_in_ob(tmp, op);
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;
812  FOR_INV_PREPARE(tmp, inv) {
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) {
828  force = create_archetype(FORCE_NAME);
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;
852  SET_FLAG(force, FLAG_APPLIED);
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 */
875  object_insert_in_ob(force, tmp);
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;
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 */
1034  SET_FLAG(head, FLAG_UNAGGRESSIVE);
1035  object_set_enemy(head, NULL);
1036  done_one = 1;
1037  }
1038 
1039  /* berserk monsters */
1041  SET_FLAG(head, FLAG_BERSERK);
1042  done_one = 1;
1043  }
1044  /* charm */
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? */
1170  if (OB_TYPE_MOVE_BLOCK(op, GET_MAP_MOVE_BLOCK(m, x, y))) {
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 */
1241  if (GET_MAP_MOVE_BLOCK(m, x, y)&MOVE_FLY_LOW)
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)
Adjust the range of the spell based on level.
Definition: spell_util.cpp:338
object_was_destroyed
#define object_was_destroyed(op, old_tag)
Checks if an object still exists.
Definition: object.h:70
object_value_set
bool object_value_set(const object *op, const char *const key)
Determine if an extra value is set.
Definition: object.cpp:4376
object::name_pl
sstring name_pl
The plural name of the object.
Definition: object.h:323
FORCE_CHANGE_ABILITY
#define FORCE_CHANGE_ABILITY
Definition: spells.h:145
living::exp
int64_t exp
Experience.
Definition: living.h:47
PLAYER
@ PLAYER
Definition: object.h:112
object_get_owner
object * object_get_owner(object *op)
Returns the object which this object marks as being the owner.
Definition: object.cpp:804
set_spell_skill
void set_spell_skill(object *op, object *caster, object *spob, object *dest)
Utility function to assign the correct skill when casting.
Definition: spell_util.cpp:94
global.h
make_object_glow
static int make_object_glow(object *op, int radius, int time)
Makes living objects glow.
Definition: spell_attack.cpp:665
object_get_env_recursive
object * object_get_env_recursive(object *op)
Utility function.
Definition: object.cpp:590
INS_NO_WALK_ON
#define INS_NO_WALK_ON
Don't call check_walk_on against the originator.
Definition: object.h:582
friendly
TIPS on SURVIVING Crossfire is populated with a wealth of different monsters These monsters can have varying immunities and attack types In some of them can be quite a bit smarter than others It will be important for new players to learn the abilities of different monsters and learn just how much it will take to kill them This section discusses how monsters can interact with players Most monsters in the game are out to mindlessly kill and destroy the players These monsters will help boost a player s after he kills them When fighting a large amount of monsters in a single attempt to find a narrower hallway so that you are not being attacked from all sides Charging into a room full of Beholders for instance would not be open the door and fight them one at a time For there are several maps designed for them Find these areas and clear them out All throughout these a player can find signs and books which they can read by stepping onto them and hitting A to apply the book sign These messages will help the player to learn the system One more always keep an eye on your food If your food drops to your character will soon so BE CAREFUL ! NPCs Non Player Character are special monsters which have intelligence Players may be able to interact with these monsters to help solve puzzles and find items of interest To speak with a monster you suspect to be a simply move to an adjacent square to them and push the double ie Enter your and press< Return > You can also use say if you feel like typing a little extra Other NPCs may not speak to but display intelligence with their movement Some monsters can be friendly
Definition: survival-guide.txt:38
object_update_turn_face
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.cpp:1332
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:724
remove_friendly_object
void remove_friendly_object(object *op)
Removes the specified object from the linked list of friendly objects.
Definition: friend.cpp:52
living::maxhp
int16_t maxhp
Max hit points.
Definition: living.h:41
AT_MAGIC
#define AT_MAGIC
Definition: attack.h:77
PATH_LIGHT
#define PATH_LIGHT
Definition: spells.h:32
llevError
@ llevError
Error, serious thing.
Definition: logger.h:11
SP_BOMB
#define SP_BOMB
Definition: spells.h:82
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
FLAG_UNDEAD
#define FLAG_UNDEAD
Monster is undead.
Definition: define.h:270
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
FLAG_GENERATOR
#define FLAG_GENERATOR
Will generate type ob->stats.food.
Definition: define.h:248
get_fear_bonus
int get_fear_bonus(int stat)
Definition: living.cpp:2397
SP_FAERY_FIRE
#define SP_FAERY_FIRE
Definition: spells.h:118
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
fire_swarm
int fire_swarm(object *op, object *caster, object *spell, int dir)
The following routine creates a swarm of objects.
Definition: spell_attack.cpp:1088
object::attack_movement
uint16_t attack_movement
What kind of attack movement.
Definition: object.h:401
absdir
int absdir(int d)
Computes an absolute direction.
Definition: object.cpp:3714
tailor_god_spell
int tailor_god_spell(object *spellop, object *caster)
Changes the attributes of cone, smite, and ball spells as needed by the code.
Definition: gods.cpp:1223
object::range
int8_t range
Range of the spell.
Definition: object.h:417
object::speed
float speed
Frequency of object 'moves' relative to server tick rate.
Definition: object.h:337
object_set_enemy
void object_set_enemy(object *op, object *enemy)
Sets the enemy of an object.
Definition: object.cpp:915
object::invisible
int16_t invisible
How much longer the object will be invis.
Definition: object.h:370
living::Dex
int8_t Dex
Definition: living.h:36
object::x
int16_t x
Definition: object.h:335
mood_change
int mood_change(object *op, object *caster, object *spell)
This covers the various spells that change the moods of monsters - makes them angry,...
Definition: spell_attack.cpp:904
object::speed_left
float speed_left
How much speed is left to spend this round.
Definition: object.h:338
PREFER_LOW
#define PREFER_LOW
Definition: define.h:558
object::map
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
infect_object
int infect_object(object *victim, object *disease, int force)
Try to infect something with a disease.
Definition: disease.cpp:317
MoveType
unsigned char MoveType
Typdef here to define type large enough to hold bitmask of all movement types.
Definition: define.h:417
object_set_owner
void object_set_owner(object *op, object *owner)
Sets the owner and sets the skill and exp pointers to owner's current skill and experience objects.
Definition: object.cpp:840
get_pointed_target
static object * get_pointed_target(object *op, int dir, int range, int type)
Returns the pointer to the first monster in the direction which is pointed to by op.
Definition: spell_attack.cpp:496
create_bomb
int create_bomb(object *op, object *caster, int dir, object *spell)
Create a bomb.
Definition: spell_attack.cpp:447
SP_CONE
#define SP_CONE
Definition: spells.h:81
time
non standard information is not specified or uptime this means how long since the executable has been started A particular host may have been running a server for quite a long time
Definition: arch-handbook.txt:206
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,...) PRINTF_ARGS(6
MIN
#define MIN(x, y)
Definition: compat.h:21
MSG_TYPE_VICTIM_SPELL
#define MSG_TYPE_VICTIM_SPELL
Someone cast a bad spell on the player.
Definition: newclient.h:657
SP_level_duration_adjust
int SP_level_duration_adjust(const object *caster, const object *spob)
Adjust the duration of the spell based on level.
Definition: spell_util.cpp:312
object::direction
int8_t direction
Means the object is moving that way.
Definition: object.h:344
object::count
tag_t count
Unique object number for this object.
Definition: object.h:307
object::last_grace
int16_t last_grace
As last_sp, except for grace.
Definition: object.h:369
RUNE
@ RUNE
Definition: object.h:245
change_skill
int change_skill(object *who, object *new_skill, int flag)
This changes the object's skill to new_skill.
Definition: skill_util.cpp:359
fix_object
void fix_object(object *op)
Updates all abilities given by applied objects in the inventory of the given object.
Definition: living.cpp:1132
DIRX
#define DIRX(xyz)
Definition: define.h:457
hit_map
int hit_map(object *op, int dir, uint32_t type, int full_hit)
Attack a spot on the map.
Definition: attack.cpp:355
P_NO_MAGIC
#define P_NO_MAGIC
Spells (some) can't pass this object.
Definition: map.h:227
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
object::title
sstring title
Of foo, etc.
Definition: object.h:325
object_get_value
const char * object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.cpp:4346
P_IS_ALIVE
#define P_IS_ALIVE
Something alive is on this space.
Definition: map.h:237
FLAG_APPLIED
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:235
object::level
int16_t level
Level of creature or object.
Definition: object.h:361
object_insert_in_ob
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.cpp:2857
HUGE_BUF
#define HUGE_BUF
Used for messages - some can be quite long.
Definition: define.h:37
MSG_TYPE_VICTIM
#define MSG_TYPE_VICTIM
Something bad is happening to the player.
Definition: newclient.h:418
AT_DEATH
#define AT_DEATH
Definition: attack.h:93
object::resist
int16_t resist[NROFATTACKS]
Resistance adjustments for attacks.
Definition: object.h:351
find_god
const object * find_god(const char *name)
Returns a god's object from its name.
Definition: holy.cpp:317
draw_ext_info
vs only yadda is in because all tags get reset on the next draw_ext_info In the second since it is all in one draw_ext_info
Definition: media-tags.txt:61
FLAG_ALIVE
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:230
object::path_denied
uint32_t path_denied
Paths the object is denied access to.
Definition: object.h:355
cone_drop
void cone_drop(object *op)
Drops an object based on what is in the cone's "other_arch".
Definition: spell_attack.cpp:265
MSG_TYPE_SPELL_SUCCESS
#define MSG_TYPE_SPELL_SUCCESS
Spell succeeded messages.
Definition: newclient.h:638
check_bullet
void check_bullet(object *op)
Checks to see what op should do, given the space it is on (eg, explode, damage player,...
Definition: spell_attack.cpp:217
object::path_repelled
uint32_t path_repelled
Paths the object is repelled from.
Definition: object.h:354
object::y
int16_t y
Position in the map for this object.
Definition: object.h:335
m
static event_registration m
Definition: citylife.cpp:422
FLAG_NO_ATTACK
#define FLAG_NO_ATTACK
monster don't attack
Definition: define.h:355
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects,...
Definition: object.cpp:1560
cast_light
int cast_light(object *op, object *caster, object *spell, int dir)
Illuminates something on a map, or try to blind a living thing.
Definition: spell_attack.cpp:1136
PREFER_HIGH
#define PREFER_HIGH
Definition: define.h:557
explode_bullet
void explode_bullet(object *op)
Causes an object to explode, eg, a firebullet, poison cloud ball, etc.
Definition: spell_attack.cpp:121
object::subtype
uint8_t subtype
Subtype of object.
Definition: object.h:349
add_refcount
sstring add_refcount(sstring str)
This will increase the refcount of the string str.
Definition: shstr.cpp:210
determine_god
const char * determine_god(object *op)
Determines if op worships a god.
Definition: gods.cpp:55
freearr_y
short freearr_y[SIZEOFFREE]
Y offset when searching around a spot.
Definition: object.cpp:305
ARCH_DETECT_MAGIC
#define ARCH_DETECT_MAGIC
Archetype for detect magic spell.
Definition: object.h:589
query_name
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.cpp:588
MOVE_WALK
#define MOVE_WALK
Object walks.
Definition: define.h:392
object::spell
object * spell
Spell that was being cast.
Definition: object.h:420
HEAD
#define HEAD(op)
Returns the head part of an object.
Definition: object.h:607
object::move_type
MoveType move_type
Type of movement this object uses.
Definition: object.h:436
SPELL_GRACE
#define SPELL_GRACE
Definition: spells.h:59
out_of_map
int out_of_map(mapstruct *m, int x, int y)
Return 1 if coordinates X and Y are out of the map M, taking into account tiling.
Definition: map.cpp:2306
object::last_eat
int32_t last_eat
How long since we last ate.
Definition: object.h:366
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
INS_NO_MERGE
#define INS_NO_MERGE
Don't try to merge with other items.
Definition: object.h:580
living::dam
int16_t dam
How much damage this object does when hitting.
Definition: living.h:46
object::magic
int8_t magic
Any magical bonuses to this item.
Definition: object.h:358
spell
with a maximum of six This is not so if you are wearing plate you receive no benefit Armour is additive with all the supplementry forms of which means that it lasts until the next semi permanent spell effect is cast upon the character spell
Definition: tome-of-magic.txt:44
GET_MAP_MOVE_BLOCK
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Gets the blocking state of a square.
Definition: map.h:192
FOR_INV_FINISH
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:671
object::move_on
MoveType move_on
Move types affected moving on to this space.
Definition: object.h:439
living::food
int32_t food
How much food in stomach.
Definition: living.h:48
caster_level
int caster_level(const object *caster, const object *spell)
This function returns the effective level the spell is being cast at.
Definition: spell_util.cpp:194
FLAG_UNAGGRESSIVE
#define FLAG_UNAGGRESSIVE
Monster doesn't attack players.
Definition: define.h:272
tag_t
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:14
sproto.h
living::sp
int16_t sp
Spell points.
Definition: living.h:42
cast_curse
int cast_curse(object *op, object *caster, object *spell_ob, int dir)
Curse an object, reducing its statistics.
Definition: spell_attack.cpp:800
MSG_TYPE_SPELL
#define MSG_TYPE_SPELL
Spell related info.
Definition: newclient.h:414
map_find_by_flag
object * map_find_by_flag(mapstruct *map, int x, int y, int flag)
Finds an object in a map tile by flag number.
Definition: map.cpp:2634
random_roll
int random_roll(int min, int max, const object *op, int goodbad)
Roll a random number between min and max.
Definition: utils.cpp:42
object::race
sstring race
Human, goblin, dragon, etc.
Definition: object.h:326
object::facing
int8_t facing
Object is oriented/facing that way.
Definition: object.h:345
object_insert_in_map_at
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.cpp:2100
SP_DESTRUCTION
#define SP_DESTRUCTION
Definition: spells.h:90
object::other_arch
struct archetype * other_arch
Pointer used for various things - mostly used for what this objects turns into or what this object cr...
Definition: object.h:425
FLAG_MONSTER
#define FLAG_MONSTER
Will attack players.
Definition: define.h:245
find_skill_by_name
object * find_skill_by_name(object *who, const char *name)
This returns the skill pointer of the given name (the one that accumulates exp, has the level,...
Definition: skill_util.cpp:211
P_OUT_OF_MAP
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:249
env
static std::shared_ptr< inja::Environment > env
Rendering environment.
Definition: mapper.cpp:2222
INS_ON_TOP
#define INS_ON_TOP
Always put object on top.
Definition: object.h:583
d
How to Install a Crossfire Server on you must install a python script engine on your computer Python is the default script engine of Crossfire You can find the python engine you have only to install them The VisualC Crossfire settings are for d
Definition: INSTALL_WIN32.txt:13
create_archetype
object * create_archetype(const char *name)
Finds which archetype matches the given name, and returns a new object containing a copy of the arche...
Definition: arch.cpp:276
free_string
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.cpp:280
living::wc
int8_t wc
Weapon Class, lower WC increases probability of hitting.
Definition: living.h:37
FREE_AND_CLEAR_STR
#define FREE_AND_CLEAR_STR(xyz)
Release the shared string, and set it to NULL.
Definition: global.h:200
MOVE_FLY_LOW
#define MOVE_FLY_LOW
Low flying object.
Definition: define.h:393
living::maxgrace
int16_t maxgrace
Maximum grace.
Definition: living.h:45
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:717
change_abil
int change_abil(object *op, object *tmp)
Permanently alters an object's stats/flags based on another object.
Definition: living.cpp:394
cast_smite_spell
int cast_smite_spell(object *op, object *caster, int dir, object *spell)
The priest points to a creature and causes a 'godly curse' to descend.
Definition: spell_attack.cpp:546
living::Wis
int8_t Wis
Definition: living.h:36
sounds.h
FLAG_REMOVED
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:232
FLAG_REFL_SPELL
#define FLAG_REFL_SPELL
Spells (some) will reflect from object.
Definition: define.h:275
object::dam_modifier
uint8_t dam_modifier
How going up in level affects damage.
Definition: object.h:419
NDI_UNIQUE
#define NDI_UNIQUE
Print immediately, don't buffer.
Definition: newclient.h:265
object::slaying
sstring slaying
Which race to do double damage to.
Definition: object.h:327
object::glow_radius
int8_t glow_radius
indicates the glow radius of the object
Definition: object.h:374
FLAG_FRIENDLY
#define FLAG_FRIENDLY
Will help players.
Definition: define.h:246
spells.h
object::name
sstring name
The name of the object, obviously...
Definition: object.h:319
ob_process
method_ret ob_process(object *op)
Processes an object, giving it the opportunity to move or react.
Definition: ob_methods.cpp:67
SP_level_dam_adjust
int SP_level_dam_adjust(const object *caster, const object *spob)
Returns adjusted damage based on the caster.
Definition: spell_util.cpp:287
MSG_TYPE_SPELL_FAILURE
#define MSG_TYPE_SPELL_FAILURE
Spell failure messages.
Definition: newclient.h:636
add_friendly_object
void add_friendly_object(object *op)
Add a new friendly object to the list of friendly objects.
Definition: friend.cpp:32
AT_TURN_UNDEAD
#define AT_TURN_UNDEAD
Definition: attack.h:89
get_map_flags
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.cpp:300
living::maxsp
int16_t maxsp
Max spell points.
Definition: living.h:43
mapstruct
This is a game-map.
Definition: map.h:315
object::env
object * env
Pointer to the object which is the environment.
Definition: object.h:301
object::last_sp
int32_t last_sp
As last_heal, but for spell points.
Definition: object.h:368
living::Cha
int8_t Cha
Definition: living.h:36
object::skill
sstring skill
Name of the skill this object uses/grants.
Definition: object.h:329
MSG_TYPE_SPELL_ERROR
#define MSG_TYPE_SPELL_ERROR
Spell failure messages.
Definition: newclient.h:639
get_turn_bonus
int get_turn_bonus(int stat)
Definition: living.cpp:2385
did_make_save
int did_make_save(const object *op, int level, int bonus)
This function takes an object (monster/player, op), and determines if it makes a basic save throw by ...
Definition: living.cpp:2293
FLAG_REFLECTING
#define FLAG_REFLECTING
Object reflects from walls (lightning)
Definition: define.h:262
SPELL_EFFECT
@ SPELL_EFFECT
Definition: object.h:220
ATNR_MAGIC
#define ATNR_MAGIC
Definition: attack.h:50
hit_player
int hit_player(object *op, int dam, object *hitter, uint32_t type, int full_hit)
Object is attacked by something.
Definition: attack.cpp:1907
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
cast_cause_disease
int cast_cause_disease(object *op, object *caster, object *spell, int dir)
Let's try to infect something.
Definition: spell_attack.cpp:1207
living::ac
int8_t ac
Armor Class, lower AC increases probability of not getting hit.
Definition: living.h:38
share_exp
void share_exp(object *op, int64_t exp, const char *skill, int flag)
Gives experience to a player/monster, sharing it with party if applicable.
Definition: living.cpp:2323
object::duration
int16_t duration
Number of moves (see 'speed') spell lasts.
Definition: object.h:415
die_roll
int die_roll(int num, int size, const object *op, int goodbad)
Roll a number of dice (2d3, 4d6).
Definition: utils.cpp:122
arch_to_object
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.cpp:227
level
int level
Definition: readable.cpp:1563
MIN_ACTIVE_SPEED
#define MIN_ACTIVE_SPEED
Cut off point of when an object is put on the active list or not.
Definition: define.h:633
FLAG_IS_USED_UP
#define FLAG_IS_USED_UP
When (–food<0) the object will exit.
Definition: define.h:260
FLAG_BERSERK
#define FLAG_BERSERK
monster will attack closest living object
Definition: define.h:352
AT_FEAR
#define AT_FEAR
Definition: attack.h:90
AT_GODPOWER
#define AT_GODPOWER
Definition: attack.h:96
skill
skill
Definition: arch-handbook.txt:585
SWARM_SPELL
#define SWARM_SPELL
Definition: spells.h:166
object_remove
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.cpp:1833
OB_TYPE_MOVE_BLOCK
#define OB_TYPE_MOVE_BLOCK(ob1, type)
Basic macro to see if if ob1 can not move onto a space based on the 'type' move_block parameter Add c...
Definition: define.h:426
P_NO_CLERIC
#define P_NO_CLERIC
No clerical spells cast here.
Definition: map.h:238
object_copy_owner
void object_copy_owner(object *op, object *clone)
Set the owner to clone's current owner and set the skill and experience objects to clone's objects (t...
Definition: object.cpp:893
SK_EXP_ADD_SKILL
#define SK_EXP_ADD_SKILL
Give the player the skill.
Definition: skills.h:78
PETMOVE
#define PETMOVE
If the upper four bits of attack_movement are set to this number, the monster follows a player until ...
Definition: define.h:495
object::stats
living stats
Str, Con, Dex, etc.
Definition: object.h:378
object_set_value
int object_set_value(object *op, const char *key, const char *value, int add_key)
Updates the key in op to value.
Definition: object.cpp:4499
freearr_x
short freearr_x[SIZEOFFREE]
X offset when searching around a spot.
Definition: object.cpp:299
AT_HOLYWORD
#define AT_HOLYWORD
Definition: attack.h:97
object::attacktype
uint32_t attacktype
Bitmask of attacks this object does.
Definition: object.h:352
living.h
SP_EXPLOSION
#define SP_EXPLOSION
Definition: spells.h:80
FLAG_SLEEP
#define FLAG_SLEEP
NPC is sleeping.
Definition: define.h:307
cast_destruction
int cast_destruction(object *op, object *caster, object *spell_ob)
Hit all monsters around the caster.
Definition: spell_attack.cpp:707
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:664
living::hp
int16_t hp
Hit Points.
Definition: living.h:40
FORCE
@ FORCE
Definition: object.h:229
fire_bolt
int fire_bolt(object *op, object *caster, int dir, object *spob)
Cast a bolt-like spell.
Definition: spell_attack.cpp:61
MAX_LIGHT_RADII
#define MAX_LIGHT_RADII
Max radii for 'light' object, really large values allow objects that can slow down the game.
Definition: define.h:444
object.h
llevDebug
@ llevDebug
Only for debugging purposes.
Definition: logger.h:13
DIRY
#define DIRY(xyz)
Definition: define.h:458
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
cast_cone
int cast_cone(object *op, object *caster, int dir, object *spell)
Casts a cone spell.
Definition: spell_attack.cpp:297
FORCE_NAME
#define FORCE_NAME
Definition: spells.h:169
living::Con
int8_t Con
Definition: living.h:36
SPELL_MANA
#define SPELL_MANA
Definition: spells.h:58