Crossfire Server, Trunk  R20513
pets.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 
19 #include "global.h"
20 
21 #include <assert.h>
22 #include <ctype.h>
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include "sproto.h"
27 
34 static void mark_inventory_as_no_drop(object *ob) {
35  FOR_INV_PREPARE(ob, tmp)
36  SET_FLAG(tmp, FLAG_NO_DROP);
38 }
39 
57 object *pets_get_enemy(object *pet, rv_vector *rv) {
58  object *owner, *tmp, *attacker, *tmp3;
59  int i;
60  int16_t x, y;
61  mapstruct *nm;
62  int search_arr[SIZEOFFREE];
63  int mflags;
64 
65  attacker = pet->attacked_by; /*pointer to attacking enemy*/
66  pet->attacked_by = NULL; /*clear this, since we are dealing with it*/
67 
68  owner = object_get_owner(pet);
69  if (owner != NULL) {
70  /* If the owner has turned on the pet, make the pet
71  * unfriendly.
72  */
73  if (monster_check_enemy(owner, rv) == pet) {
76  pet->attack_movement &= ~PETMOVE;
77  return owner;
78  }
79  } else {
80  /* else the owner is no longer around, so the
81  * pet no longer needs to be friendly.
82  */
85  pet->attack_movement &= ~PETMOVE;
86  return NULL;
87  }
88  /* If they are not on the same map, the pet won't be agressive */
89  if (!on_same_map(pet, owner))
90  return NULL;
91 
92  /* See if the pet has an existing enemy. If so, don't start a new one*/
93  tmp = monster_check_enemy(pet, rv);
94  if (tmp != NULL) {
95  if (tmp != owner || QUERY_FLAG(pet, FLAG_CONFUSED) || !QUERY_FLAG(pet, FLAG_FRIENDLY))
96  return tmp;
97 
98  /* without this check, you can actually get pets with
99  * enemy set to owner!
100  */
101  object_set_enemy(pet, NULL);
102  }
103  get_search_arr(search_arr);
104 
105  if (owner->type == PLAYER && owner->contr->petmode == pet_sad) {
107  if (tmp != NULL && get_rangevector(pet, tmp, rv, 0) && monster_check_enemy(pet, rv) != NULL)
108  return tmp;
109  /* if we got here we have no enemy */
110  /* we return NULL to avoid heading back to the owner */
111  object_set_enemy(pet, NULL);
112  return NULL;
113  }
114 
115  /* Since the pet has no existing enemy, look for anything nasty
116  * around the owner that it should go and attack.
117  */
118  tmp3 = NULL;
119  for (i = 0; i < SIZEOFFREE; i++) {
120  x = owner->x+freearr_x[search_arr[i]];
121  y = owner->y+freearr_y[search_arr[i]];
122  nm = owner->map;
123  /* Only look on the space if there is something alive there. */
124  mflags = get_map_flags(nm, &nm, x, y, &x, &y);
125  if (!(mflags&P_OUT_OF_MAP) && mflags&P_IS_ALIVE) {
126  FOR_MAP_PREPARE(nm, x, y, tmp) {
127  object *tmp2 = HEAD(tmp);
128 
129  if (QUERY_FLAG(tmp2, FLAG_ALIVE)
130  && ((!QUERY_FLAG(tmp2, FLAG_FRIENDLY) && tmp2->type != PLAYER) || pets_should_arena_attack(pet, owner, tmp2))
131  && !QUERY_FLAG(tmp2, FLAG_UNAGGRESSIVE)
132  && tmp2 != pet
133  && tmp2 != owner
134  && monster_can_detect_enemy(pet, tmp2, rv)) {
135  if (!monster_can_see_enemy(pet, tmp2)) {
136  if (tmp3 == NULL)
137  tmp3 = tmp2;
138  } else {
139  object_set_enemy(pet, tmp2);
140  if (monster_check_enemy(pet, rv) != NULL)
141  return tmp2;
142  object_set_enemy(pet, NULL);
143  }
144  }/* if this is a valid enemy */
145  } FOR_MAP_FINISH();/* for objects on this space */
146  }/* if there is something living on this space */
147  } /* for loop of spaces around the owner */
148 
149  /* fine, we went through the whole loop and didn't find one we could
150  see, take what we have */
151  if (tmp3 != NULL) {
152  object_set_enemy(pet, tmp3);
153  if (monster_check_enemy(pet, rv) != NULL)
154  return tmp3;
155  object_set_enemy(pet, NULL);
156  }
157 
158  /* No threat to owner, check to see if the pet has an attacker*/
159  if (attacker != NULL) {
160  /* need to be sure this is the right one! */
161  if (attacker->count == pet->attacked_by_count) {
162  /* also need to check to make sure it is not freindly */
163  /* or otherwise non-hostile, and is an appropriate target */
164  if (!QUERY_FLAG(attacker, FLAG_FRIENDLY) && on_same_map(pet, attacker)) {
165  object_set_enemy(pet, attacker);
166  if (monster_check_enemy(pet, rv) != NULL)
167  return attacker;
168  object_set_enemy(pet, NULL);
169  }
170  }
171  }
172 
173  /* Don't have an attacker or legal enemy, so look for a new one!.
174  * This looks for one around where the pet is. Thus, you could lead
175  * a pet to danger, then take a few steps back. This code is basically
176  * the same as the code that looks around the owner.
177  */
178  if (owner->type == PLAYER && owner->contr->petmode != pet_defend) {
179  tmp3 = NULL;
180  for (i = 0; i < SIZEOFFREE; i++) {
181  x = pet->x+freearr_x[search_arr[i]];
182  y = pet->y+freearr_y[search_arr[i]];
183  nm = pet->map;
184  /* Only look on the space if there is something alive there. */
185  mflags = get_map_flags(nm, &nm, x, y, &x, &y);
186  if (!(mflags&P_OUT_OF_MAP) && mflags&P_IS_ALIVE) {
187  FOR_MAP_PREPARE(nm, x, y, tmp) {
188  object *tmp2 = HEAD(tmp);
189  if (QUERY_FLAG(tmp2, FLAG_ALIVE)
190  && ((!QUERY_FLAG(tmp2, FLAG_FRIENDLY) && tmp2->type != PLAYER) || pets_should_arena_attack(pet, owner, tmp2))
191  && !QUERY_FLAG(tmp2, FLAG_UNAGGRESSIVE)
192  && tmp2 != pet
193  && tmp2 != owner
194  && monster_can_detect_enemy(pet, tmp2, rv)) {
195  if (!monster_can_see_enemy(pet, tmp2)) {
196  assert(tmp3 == NULL);
197  } else {
198  object_set_enemy(pet, tmp2);
199  if (monster_check_enemy(pet, rv) != NULL)
200  return tmp2;
201  object_set_enemy(pet, NULL);
202  }
203  } /* make sure we can get to the bugger */
204  } FOR_MAP_FINISH();/* for objects on this space */
205  } /* if there is something living on this space */
206  } /* for loop of spaces around the pet */
207  } /* pet in defence mode */
208 
209  /* fine, we went through the whole loop and didn't find one we could
210  see, take what we have */
211  if (tmp3 != NULL) {
212  object_set_enemy(pet, tmp3);
213  if (monster_check_enemy(pet, rv) != NULL)
214  return tmp3;
215  object_set_enemy(pet, NULL);
216  }
217 
218  /* Didn't find anything - return the owner's enemy or NULL */
219  return monster_check_enemy(pet, rv);
220 }
221 
231 void pets_terminate_all(object *owner) {
232  objectlink *obl, *next;
233 
234  for (obl = first_friendly_object; obl != NULL; obl = next) {
235  object *ob = obl->ob;
236  next = obl->next;
237  if (object_get_owner(ob) == owner) {
238  if (!QUERY_FLAG(ob, FLAG_REMOVED))
239  object_remove(ob);
242  }
243  }
244 }
245 
257 void pets_remove_all(void) {
258  objectlink *obl, *next;
259  object *owner;
260 
261  for (obl = first_friendly_object; obl != NULL; obl = next) {
262  next = obl->next;
263  if (obl->ob->type != PLAYER
264  && QUERY_FLAG(obl->ob, FLAG_FRIENDLY)
265  && (owner = object_get_owner(obl->ob)) != NULL
266  && !on_same_map(owner, obl->ob)) {
267  /* follow owner checks map status for us. Note that pet can
268  * die in pets_follow_owner(), so check for obl->ob existence
269  */
270  pets_follow_owner(obl->ob, owner);
271  if (obl->ob && QUERY_FLAG(obl->ob, FLAG_REMOVED) && FABS(obl->ob->speed) > MIN_ACTIVE_SPEED) {
272  object *ob = obl->ob;
273 
274  LOG(llevMonster, "(pet failed to follow)\n");
277  }
278  }
279  }
280 }
281 
293 void pets_follow_owner(object *ob, object *owner) {
294  int dir;
295 
296  if (!QUERY_FLAG(ob, FLAG_REMOVED))
297  object_remove(ob);
298 
299  if (owner->map == NULL) {
300  LOG(llevError, "Can't follow owner: no map.\n");
301  return;
302  }
303  if (owner->map->in_memory != MAP_IN_MEMORY) {
304  LOG(llevError, "Owner of the pet not on a map in memory!?\n");
305  return;
306  }
307  dir = object_find_free_spot(ob, owner->map, owner->x, owner->y, 1, SIZEOFFREE);
308 
309  if (dir == -1) {
310  LOG(llevMonster, "No space for pet to follow, freeing %s.\n", ob->name);
311  return; /* Will be freed since it's removed */
312  }
313  object_insert_in_map_at(ob, owner->map, NULL, 0, owner->x+freearr_x[dir], owner->y+freearr_y[dir]);
314  if (owner->type == PLAYER) /* Uh, I hope this is always true... */
316  "Your pet magically appears next to you");
317  return;
318 }
319 
329 void pets_move(object *ob) {
330  int dir, i;
331  tag_t tag;
332  int16_t dx, dy;
333  object *owner;
334  mapstruct *m;
335 
336  /* Check to see if player pulled out */
337  owner = object_get_owner(ob);
338  if (owner == NULL) {
339  object_remove(ob); /* Will be freed when returning */
342  LOG(llevMonster, "Pet: no owner, leaving.\n");
343  return;
344  }
345 
346  /* move monster into the owners map if not in the same map */
347  if (!on_same_map(ob, owner)) {
348  pets_follow_owner(ob, owner);
349  return;
350  }
351  /* Calculate Direction */
352  if (owner->type == PLAYER && owner->contr->petmode == pet_sad) {
353  /* in S&D mode, if we have no enemy, run randomly about. */
354  for (i = 0; i < 15; i++) {
355  dir = get_random_dir();
356  dx = ob->x+freearr_x[dir];
357  dy = ob->y+freearr_y[dir];
358  m = ob->map;
359  if (!(get_map_flags(ob->map, &m, dx, dy, &dx, &dy)&P_OUT_OF_MAP)
360  && !OB_TYPE_MOVE_BLOCK(ob, GET_MAP_MOVE_BLOCK(m, dx, dy)))
361  break;
362  }
363  } else {
364  rv_vector rv;
365 
366  if (get_rangevector(ob, owner, &rv, 0))
367  dir = rv.direction;
368  else
369  dir = get_random_dir();
370  }
371  ob->direction = dir;
372 
373  tag = ob->count;
374  /* move_ob returns 0 if the object couldn't move. If that is the
375  * case, lets do some other work.
376  */
377  if (!move_ob(ob, dir, ob)) {
378  object *part;
379 
380  /* the failed move_ob above may destroy the pet, so check here */
381  if (object_was_destroyed(ob, tag))
382  return;
383 
384  for (part = ob; part != NULL; part = part->more) {
385  dx = part->x+freearr_x[dir];
386  dy = part->y+freearr_y[dir];
387  m = get_map_from_coord(part->map, &dx, &dy);
388  if (m == NULL)
389  continue;
390 
391  FOR_MAP_PREPARE(m, dx, dy, ob2) {
392  object *new_ob;
393 
394  new_ob = HEAD(ob2);
395  if (new_ob == ob)
396  break;
397  if (new_ob == owner)
398  return;
399  if (object_get_owner(new_ob) == owner)
400  break;
401 
402  /* Hmm. Did we try to move into an enemy monster? If so,
403  * make it our enemy.
404  */
405  if (QUERY_FLAG(new_ob, FLAG_ALIVE)
407  && !QUERY_FLAG(new_ob, FLAG_UNAGGRESSIVE)
408  && !QUERY_FLAG(new_ob, FLAG_FRIENDLY)) {
409  object_set_enemy(ob, new_ob);
410  if (new_ob->enemy == NULL)
411  object_set_enemy(new_ob, ob);
412  return;
413  } else if (new_ob->type == PLAYER) {
414  draw_ext_info(NDI_UNIQUE, 0, new_ob,
416  "You stand in the way of someones pet.");
417  return;
418  }
419  } FOR_MAP_FINISH();
420  }
421  /* Try a different course */
422  dir = absdir(dir+4-(RANDOM()%5)-(RANDOM()%5));
423  (void)move_ob(ob, dir, ob);
424  }
425  return;
426 }
427 
428 /****************************************************************************
429  *
430  * GOLEM SPELL CODE
431  *
432  ****************************************************************************/
433 
446 static object *fix_summon_pet(archetype *at, object *op, int dir) {
447  archetype *atmp;
448  object *tmp = NULL, *prev = NULL, *head = NULL;
449 
450  for (atmp = at; atmp != NULL; atmp = atmp->more) {
451  tmp = arch_to_object(atmp);
452  if (atmp == at) {
453 
454  /* Ensure the golem can actually move if no move_type defined.
455  * This check is redundant since this is checked at server startup. */
456  if (tmp->move_type == 0) {
457  LOG(llevError, "summoned %s [%s] is without move_type!\n", tmp->name, atmp->name);
458  tmp->move_type = MOVE_WALK;
459  }
460 
461  object_set_owner(tmp, op);
462  if (op->type == PLAYER) {
463  tmp->stats.exp = 0;
464  add_friendly_object(tmp);
465  SET_FLAG(tmp, FLAG_FRIENDLY);
466  CLEAR_FLAG(tmp, FLAG_MONSTER);
467  } else if (QUERY_FLAG(op, FLAG_FRIENDLY)) {
468  object *owner = object_get_owner(op);
469 
470  if (owner != NULL) {/* For now, we transfer ownership */
471  object_set_owner(tmp, owner);
472  tmp->attack_movement = PETMOVE;
473  add_friendly_object(tmp);
474  SET_FLAG(tmp, FLAG_FRIENDLY);
475  }
476  }
477  if (op->type != PLAYER) {
478  tmp->attack_movement = PETMOVE;
479  tmp->speed_left = -1;
480  tmp->type = 0;
481  object_set_enemy(tmp, op->enemy);
482  } else
483  tmp->type = GOLEM;
484  }
485  if (head == NULL)
486  head = tmp;
487  tmp->x = op->x+freearr_x[dir]+tmp->arch->clone.x;
488  tmp->y = op->y+freearr_y[dir]+tmp->arch->clone.y;
489  tmp->map = op->map;
490  if (tmp->invisible)
491  tmp->invisible = 0;
492  if (head != tmp)
493  tmp->head = head,
494  prev->more = tmp;
495  prev = tmp;
496  }
497  head->direction = dir;
498 
499  if (head->randomitems) {
500  create_treasure(head->randomitems, head, GT_STARTEQUIP, 6, 0);
501  if (QUERY_FLAG(head, FLAG_MONSTER)) {
503  }
504  }
506 
507  /* need to change some monster attr to prevent problems/crashing */
508  head->last_heal = 0;
509  head->last_eat = 0;
510  head->last_grace = 0;
511  head->last_sp = 0;
512  head->other_arch = NULL;
513  head->stats.exp = 0;
514  CLEAR_FLAG(head, FLAG_CHANGING);
516  CLEAR_FLAG(head, FLAG_GENERATOR);
517  CLEAR_FLAG(head, FLAG_SPLITTING);
518  if (head->attacktype&AT_GHOSTHIT)
519  head->attacktype = (AT_PHYSICAL|AT_DRAIN);
520 
521  return head;
522 }
523 
534 void pets_move_golem(object *op) {
535  int made_attack = 0;
536  object *tmp;
537  tag_t tag;
538  object *owner;
539 
540  if (QUERY_FLAG(op, FLAG_MONSTER))
541  return; /* Has already been moved */
542 
543  owner = object_get_owner(op);
544  if (owner == NULL) {
545  LOG(llevDebug, "Golem without owner destructed.\n");
546  object_remove(op);
548  return;
549  }
550  /* It would be nice to have a cleaner way of what message to print
551  * when the golem expires than these hard coded entries.
552  * Note it is intentional that a golems duration is based on its
553  * hp, and not duration
554  */
555  if (--op->stats.hp < 0) {
556  if (op->msg != NULL)
558  op->msg);
559  owner->contr->ranges[range_golem] = NULL;
560  owner->contr->golem_count = 0;
562  object_remove(op);
564  return;
565  }
566 
567  /* Do golem attacks/movement for single & multisq golems.
568  * Assuming here that op is the 'head' object. Pass only op to
569  * move_ob (makes recursive calls to other parts)
570  * move_ob returns 0 if the creature was not able to move.
571  */
572  tag = op->count;
573  if (move_ob(op, op->direction, op))
574  return;
575  if (object_was_destroyed(op, tag))
576  return;
577 
578  for (tmp = op; tmp; tmp = tmp->more) {
579  int16_t x = tmp->x+DIRX(op), y = tmp->y+DIRY(op);
580  object *victim;
581  mapstruct *m;
582  int mflags;
583 
584  m = op->map;
585  mflags = get_map_flags(m, &m, x, y, &x, &y);
586 
587  if (mflags&P_OUT_OF_MAP)
588  continue;
589 
590  victim = NULL;
591  FOR_MAP_PREPARE(op->map, x, y, tmp)
592  if (QUERY_FLAG(tmp, FLAG_ALIVE)) {
593  victim = tmp;
594  break;
595  }
596  FOR_MAP_FINISH();
597 
598  /* We used to call will_hit_self to make sure we don't
599  * hit ourselves, but that didn't work, and I don't really
600  * know if that was more efficient anyways than this.
601  * This at least works. Note that victim->head can be NULL,
602  * but since we are not trying to dereferance that pointer,
603  * that isn't a problem.
604  */
605  if (victim != NULL && victim != op && victim->head != op) {
606  /* for golems with race fields, we don't attack
607  * aligned races
608  */
609 
610  if (victim->race != NULL && op->race != NULL && strstr(op->race, victim->race)) {
611  if (owner != NULL)
614  "%s avoids damaging %s.",
615  op->name, victim->name);
616  } else if (victim == owner) {
617  if (owner != NULL)
620  "%s avoids damaging you.",
621  op->name);
622  } else {
623  attack_ob(victim, op);
624  made_attack = 1;
625  }
626  } /* If victim */
627  }
628  if (made_attack)
630 }
631 
648 void pets_control_golem(object *op, int dir) {
649  op->direction = dir;
650 }
651 
672 int pets_summon_golem(object *op, object *caster, int dir, object *spob) {
673  object *tmp;
674  const object *god = NULL;
675  archetype *at;
676  char buf[MAX_BUF];
677 
678  /* Because there can be different golem spells, player may want to
679  * 'lose' their old golem.
680  */
681  if (op->type == PLAYER
682  && op->contr->ranges[range_golem] != NULL
683  && op->contr->golem_count == op->contr->ranges[range_golem]->count) {
684  draw_ext_info(NDI_UNIQUE, 0, op,
686  "You dismiss your existing golem.");
689  op->contr->ranges[range_golem] = NULL;
690  op->contr->golem_count = -1;
691  }
692 
693  if (spob->other_arch != NULL)
694  at = spob->other_arch;
695  else if (spob->race != NULL) {
696  god = find_god(determine_god(caster));
697  if (god == NULL) {
700  "You must worship a god to cast %s.",
701  spob->name);
702  return 0;
703  }
704 
705  at = determine_holy_arch(god, spob->race);
706  if (at == NULL) {
709  "%s has no %s for you to call.",
710  god->name, spob->race);
711  return 0;
712  }
713  } else {
714  LOG(llevError, "Spell %s lacks other_arch\n", spob->name);
715  return 0;
716  }
717 
718  if (!dir)
719  dir = object_find_free_spot(NULL, op->map, op->x, op->y, 1, SIZEOFFREE1+1);
720 
721  if (dir == -1
722  || ob_blocked(&at->clone, op->map, op->x+freearr_x[dir], op->y+freearr_y[dir])) {
723  draw_ext_info(NDI_UNIQUE, 0, op,
725  "There is something in the way.");
726  return 0;
727  }
728  /* basically want to get proper map/coordinates for this object */
729  tmp = fix_summon_pet(at, op, dir);
730  if (tmp == NULL) {
731  draw_ext_info(NDI_UNIQUE, 0, op,
733  "Your spell fails.");
734  return 0;
735  }
736 
737  if (op->type == PLAYER) {
738  tmp->type = GOLEM;
739  object_set_owner(tmp, op);
740  set_spell_skill(op, caster, spob, tmp);
741  op->contr->ranges[range_golem] = tmp;
742  op->contr->golem_count = tmp->count;
743  /* give the player control of the golem */
744  op->contr->shoottype = range_golem;
745  } else {
746  if (QUERY_FLAG(op, FLAG_FRIENDLY)) {
747  object *owner = object_get_owner(op);
748 
749  if (owner != NULL) { /* For now, we transfer ownership */
750  object_set_owner(tmp, owner);
751  tmp->attack_movement = PETMOVE;
752  add_friendly_object(tmp);
753  set_spell_skill(op, caster, spob, tmp);
754  SET_FLAG(tmp, FLAG_FRIENDLY);
755  }
756  }
757  SET_FLAG(tmp, FLAG_MONSTER);
758  }
759 
760  /* make the speed positive.*/
761  tmp->speed = FABS(tmp->speed);
762 
763  /* This sets the level dependencies on dam and hp for monsters */
764  /* players can't cope with too strong summonings. */
765  /* but monsters can. reserve these for players. */
766  if (op->type == PLAYER) {
767  tmp->stats.hp += spob->duration+SP_level_duration_adjust(caster, spob);
768  tmp->stats.maxhp = tmp->stats.hp;
769  if (!spob->stats.dam)
770  tmp->stats.dam += SP_level_dam_adjust(caster, spob);
771  else
772  tmp->stats.dam = spob->stats.dam+SP_level_dam_adjust(caster, spob);
773  tmp->speed += .02*SP_level_range_adjust(caster, spob);
774  tmp->speed = MIN(tmp->speed, 1.0);
775  if (spob->attacktype)
776  tmp->attacktype = spob->attacktype;
777  }
778  tmp->stats.wc -= SP_level_wc_adjust(caster, spob);
779 
780  /* limit the speed to 0.3 for non-players, 1 for players. */
781 
782  /* make experience increase in proportion to the strength.
783  * this is a bit simplistic - we are basically just looking at how
784  * often the sp doubles and use that as the ratio.
785  */
786  tmp->stats.exp *= 1+(MAX(spob->stats.maxgrace, spob->stats.sp)/caster_level(caster, spob));
787  tmp->speed_left = 0;
788  tmp->direction = dir;
789 
790  /* Holy spell - some additional tailoring */
791  if (god != NULL) {
792  object *tmp2;
793 
794  snprintf(buf, sizeof(buf), "%s of %s", spob->name, god->name);
795  buf[0] = toupper(buf[0]);
796  for (tmp2 = tmp; tmp2; tmp2 = tmp2->more) {
797  if (tmp2->name != NULL)
798  free_string(tmp2->name);
799  tmp2->name = add_string(buf);
800  }
801  tmp->attacktype |= god->attacktype;
802  memcpy(tmp->resist, god->resist, sizeof(tmp->resist));
803  if (tmp->race != NULL)
804  FREE_AND_CLEAR_STR(tmp->race);
805  if (god->race != NULL)
806  tmp->race = add_string(god->race);
807  if (tmp->slaying != NULL)
809  if (god->slaying != NULL)
810  tmp->slaying = add_string(god->slaying);
811  /* safety, we must allow a god's servants some reasonable attack */
812  if (!(tmp->attacktype&AT_PHYSICAL))
813  tmp->attacktype |= AT_PHYSICAL;
814  }
815 
816  object_insert_in_map_at(tmp, tmp->map, op, 0, tmp->x, tmp->y);
817  return 1;
818 }
819 
820 /***************************************************************************
821  *
822  * Summon monster/pet/other object code
823  *
824  ***************************************************************************/
825 
840 static object *choose_cult_monster(object *pl, const object *god, int summon_level) {
841  char buf[MAX_BUF];
842  const char *race;
843  int racenr, mon_nr, i;
844  racelink *list;
845  objectlink *tobl;
846  object *otmp;
847 
848  /* Determine the number of races available */
849  racenr = 0;
850  safe_strncpy(buf, god->race, sizeof(buf));
851  race = strtok(buf, ",");
852  while (race) {
853  racenr++;
854  race = strtok(NULL, ",");
855  }
856 
857  /* next, randomly select a race from the aligned_races string */
858  if (racenr > 1) {
859  racenr = rndm(0, racenr-1);
860  safe_strncpy(buf, god->race, sizeof(buf));
861  race = strtok(buf, ",");
862  for (i = 0; i < racenr; i++)
863  race = strtok(NULL, ",");
864  } else
865  race = god->race;
866 
867 
868  /* see if a we can match a race list of monsters. This should not
869  * happen, so graceful recovery isn't really needed, but this sanity
870  * checking is good for cases where the god archetypes mismatch the
871  * race file
872  */
873  list = find_racelink(race);
874  if (list == NULL) {
877  "The spell fails! %s's creatures are beyond the range of your summons",
878  god->name);
879  LOG(llevDebug, "choose_cult_monster() requested non-existent aligned race!\n");
880  return NULL;
881  }
882 
883  /* search for an apprplritate monster on this race list */
884  mon_nr = 0;
885  for (tobl = list->member; tobl; tobl = tobl->next) {
886  otmp = tobl->ob;
887  if (otmp == NULL || !QUERY_FLAG(otmp, FLAG_MONSTER))
888  continue;
889  if (otmp->level <= summon_level)
890  mon_nr++;
891  }
892 
893  /* If this god has multiple race entries, we should really choose another.
894  * But then we either need to track which ones we have tried, or just
895  * make so many calls to this function, and if we get so many without
896  * a valid entry, assuming nothing is available and quit.
897  */
898  if (!mon_nr)
899  return NULL;
900 
901  mon_nr = rndm(0, mon_nr-1);
902  for (tobl = list->member; tobl; tobl = tobl->next) {
903  otmp = tobl->ob;
904  if (otmp == NULL || !QUERY_FLAG(otmp, FLAG_MONSTER))
905  continue;
906  if (otmp->level <= summon_level && !mon_nr--)
907  return otmp;
908  }
909  /* This should not happen */
910  LOG(llevDebug, "choose_cult_monster() mon_nr was set, but did not find a monster\n");
911  return NULL;
912 }
913 
935 int pets_summon_object(object *op, object *caster, object *spell_ob, int dir, const char *stringarg) {
936  int16_t x, y, nrof = 1, i;
937  archetype *summon_arch;
938  int ndir, mult;
939 
940  if (spell_ob->other_arch != NULL) {
941  summon_arch = spell_ob->other_arch;
942  } else if (spell_ob->randomitems != NULL) {
943  int level = caster_level(caster, spell_ob);
944  treasure *tr, *lasttr = NULL;
945 
946  /* In old code, this was a very convuluted for statement,
947  * with all the checks in the 'for' portion itself. Much
948  * more readable to break some of the conditions out.
949  */
950  for (tr = spell_ob->randomitems->items; tr; tr = tr->next) {
951  if (level < tr->magic)
952  break;
953  lasttr = tr;
954  if (stringarg != NULL && !strcmp(tr->item->name, stringarg))
955  break;
956  if (tr->next == NULL || tr->next->item == NULL)
957  break;
958  }
959  if (lasttr == NULL) {
960  LOG(llevError, "Treasurelist %s did not generate a valid entry in pets_summon_object\n", spell_ob->randomitems->name);
961  draw_ext_info(NDI_UNIQUE, 0, op,
963  "The spell fails to summon any monsters.");
964  return 0;
965  }
966  summon_arch = lasttr->item;
967  nrof = lasttr->nrof;
968  } else if (spell_ob->race != NULL && !strcmp(spell_ob->race, "GODCULTMON")) {
969  const object *god = find_god(determine_god(op));
970  object *mon, *owner;
971  int summon_level, tries;
972 
973  if (god == NULL) {
974  owner = object_get_owner(op);
975  if (owner != NULL) {
976  god = find_god(determine_god(owner));
977  }
978  }
979  /* If we can't find a god, can't get what monster to summon */
980  if (god == NULL)
981  return 0;
982 
983  if (god->race == NULL) {
986  "%s has no creatures that you may summon!",
987  god->name);
988  return 0;
989  }
990  /* the summon level */
991  summon_level = caster_level(caster, spell_ob);
992  if (summon_level == 0)
993  summon_level = 1;
994  tries = 0;
995  do {
996  mon = choose_cult_monster(op, god, summon_level);
997  if (mon == NULL) {
1000  "%s fails to send anything.",
1001  god->name);
1002  return 0;
1003  }
1004  ndir = dir;
1005  if (!ndir)
1006  ndir = object_find_free_spot(mon, op->map, op->x, op->y, 1, SIZEOFFREE);
1007  if (ndir == -1
1008  || ob_blocked(mon, op->map, op->x+freearr_x[ndir], op->y+freearr_y[ndir])) {
1009  ndir = -1;
1010  if (++tries == 5) {
1011  draw_ext_info(NDI_UNIQUE, 0, op,
1013  "There is something in the way.");
1014  return 0;
1015  }
1016  }
1017  } while (ndir == -1);
1018  if (mon->level > summon_level/2)
1019  nrof = random_roll(1, 2, op, PREFER_HIGH);
1020  else
1021  nrof = die_roll(2, 2, op, PREFER_HIGH);
1022  summon_arch = mon->arch;
1023  } else {
1024  summon_arch = NULL;
1025  }
1026 
1027  if (spell_ob->stats.dam)
1028  nrof += spell_ob->stats.dam+SP_level_dam_adjust(caster, spell_ob);
1029 
1030  if (summon_arch == NULL) {
1032  "There is no monsters available for summoning.");
1033  return 0;
1034  }
1035 
1036  if (dir) {
1037  /* Only fail if caster specified a blocked direction. */
1038  x = freearr_x[dir];
1039  y = freearr_y[dir];
1040  if (ob_blocked(&summon_arch->clone, op->map, op->x+x, op->y+y)) {
1042  "There is something in the way.");
1043  return 0;
1044  }
1045  }
1046 
1047  mult = (RANDOM()%2 ? -1 : 1);
1048 
1049  for (i = 1; i <= nrof; i++) {
1050  archetype *atmp;
1051  object *prev = NULL, *head = NULL, *tmp;
1052 
1053  if (dir) {
1054  ndir = absdir(dir+(i/2)*mult);
1055  mult = -mult;
1056  } else
1057  ndir = object_find_free_spot(&summon_arch->clone, op->map, op->x, op->y, 1, SIZEOFFREE);
1058 
1059  x = ndir > 0 ? freearr_x[ndir] : 0;
1060  y = ndir > 0 ? freearr_y[ndir] : 0;
1061  if (ndir == -1 || ob_blocked(&summon_arch->clone, op->map, op->x+x, op->y+y))
1062  continue;
1063 
1064  for (atmp = summon_arch; atmp != NULL; atmp = atmp->more) {
1065  tmp = arch_to_object(atmp);
1066  if (atmp == summon_arch) {
1067  if (QUERY_FLAG(tmp, FLAG_MONSTER)) {
1068  object_set_owner(tmp, op);
1069  set_spell_skill(op, caster, spell_ob, tmp);
1070  object_set_enemy(tmp, op->enemy);
1071  tmp->type = 0;
1072  CLEAR_FLAG(tmp, FLAG_SLEEP);
1073  if (op->type == PLAYER || QUERY_FLAG(op, FLAG_FRIENDLY)) {
1074  /* If this is not set, we make it friendly */
1075  if (!QUERY_FLAG(spell_ob, FLAG_MONSTER)) {
1076  SET_FLAG(tmp, FLAG_FRIENDLY);
1077  add_friendly_object(tmp);
1078  tmp->stats.exp = 0;
1079  if (spell_ob->attack_movement)
1080  tmp->attack_movement = spell_ob->attack_movement;
1081  if (object_get_owner(op) != NULL)
1083  }
1084  }
1085  }
1086  if (tmp->speed > MIN_ACTIVE_SPEED)
1087  tmp->speed_left = -1;
1088  }
1089  if (head == NULL)
1090  head = tmp;
1091  else {
1092  tmp->head = head;
1093  prev->more = tmp;
1094  }
1095  prev = tmp;
1096  }
1097  head->direction = freedir[ndir];
1098  head->stats.exp = 0;
1099  head = object_insert_in_map_at(head, op->map, op, 0, op->x+x, op->y+y);
1100  if (head != NULL && head->randomitems) {
1101  create_treasure(head->randomitems, head, GT_STARTEQUIP, 6, 0);
1102  if (QUERY_FLAG(head, FLAG_MONSTER)) {
1104  }
1105  }
1106  if (head != NULL) {
1108  }
1109  } /* for i < nrof */
1110  return 1;
1111 }
1112 
1122 static object *get_real_owner(object *ob) {
1123  object *realowner = ob;
1124 
1125  if (realowner == NULL)
1126  return NULL;
1127 
1128  while (object_get_owner(realowner) != NULL) {
1129  realowner = object_get_owner(realowner);
1130  }
1131  return realowner;
1132 }
1133 
1152 int pets_should_arena_attack(object *pet, object *owner, object *target) {
1153  object *rowner, *towner;
1154 
1155  /* exit if the target, pet, or owner is null. */
1156  if (target == NULL || pet == NULL || owner == NULL)
1157  return 0;
1158 
1159  /* get the owners of itself and the target, this is to deal with pets of
1160  pets */
1161  rowner = get_real_owner(owner);
1162  if (target->type != PLAYER) {
1163  towner = get_real_owner(target);
1164  } else {
1165  towner = NULL;
1166  }
1167 
1168  /* if the pet has no owner, exit with error */
1169  if (rowner == NULL) {
1170  LOG(llevError, "Pet has no owner.\n");
1171  return 0;
1172  }
1173 
1174  /* if the target is not a player, and has no owner, we shouldn't be here
1175  */
1176  if (towner == NULL && target->type != PLAYER) {
1177  LOG(llevError, "Target is not a player but has no owner. We should not be here.\n");
1178  return 0;
1179  }
1180 
1181  /* make sure that the owner is a player */
1182  if (rowner->type != PLAYER)
1183  return 0;
1184 
1185  /* abort if the petmode is not arena */
1186  if (rowner->contr->petmode != pet_arena)
1187  return 0;
1188 
1189  /* abort if the pet, it's owner, or the target is not on battleground*/
1190  if (!(op_on_battleground(pet, NULL, NULL, NULL)
1191  && op_on_battleground(owner, NULL, NULL, NULL)
1192  && op_on_battleground(target, NULL, NULL, NULL)))
1193  return 0;
1194 
1195  /* if the target is a monster, make sure it's owner is not the same */
1196  if (target->type != PLAYER && rowner == towner)
1197  return 0;
1198 
1199  /* check if the target is a player which affects how it will handle
1200  parties */
1201  if (target->type != PLAYER) {
1202  /* if the target is owned by a player make sure than make sure
1203  it's not in the same party */
1204  if (towner->type == PLAYER && rowner->contr->party != NULL) {
1205  if (rowner->contr->party == towner->contr->party)
1206  return 0;
1207  }
1208  } else {
1209  /* if the target is a player make sure than make sure it's not
1210  in the same party */
1211  if (rowner->contr->party != NULL) {
1212  if (rowner->contr->party == target->contr->party)
1213  return 0;
1214  }
1215  }
1216 
1217  return 1;
1218 }
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Sends message to player(s).
Definition: main.c:315
Error, serious thing.
Definition: logger.h:11
#define MSG_TYPE_MISC
Messages that don&#39;t go elsewhere.
Definition: newclient.h:389
#define FLAG_NO_DROP
Object can&#39;t be dropped.
Definition: define.h:289
One player.
Definition: player.h:92
const char * determine_god(object *op)
Determines if op worships a god.
Definition: gods.c:106
#define MOVE_WALK
Object walks.
Definition: define.h:407
#define UP_OBJ_FACE
Only thing that changed was the face.
Definition: object.h:519
static void mark_inventory_as_no_drop(object *ob)
Mark all inventory items as FLAG_NO_DROP.
Definition: pets.c:34
MoveType move_type
Type of movement this object uses.
Definition: object.h:424
This is used by get_rangevector to determine where the other creature is.
Definition: map.h:380
#define AT_GHOSTHIT
Definition: attack.h:85
Attack other players in arena.
Definition: player.h:48
#define FLAG_SLEEP
NPC is sleeping.
Definition: define.h:308
Used to link together several objects.
Definition: object.h:442
const char * race
Human, goblin, dragon, etc.
Definition: object.h:318
int caster_level(const object *caster, const object *spell)
This function returns the effective level the spell is being cast at.
Definition: spell_util.c:233
uint16_t attack_movement
What kind of attack movement.
Definition: object.h:391
tag_t attacked_by_count
The tag of attacker, so we can be sure.
Definition: object.h:383
#define SET_FLAG(xyz, p)
Definition: define.h:223
#define FABS(x)
Decstations have trouble with fabs()...
Definition: define.h:22
int monster_can_see_enemy(object *op, object *enemy)
Assuming no walls/barriers, lets check to see if its possible to see an enemy.
Definition: monster.c:2505
void pets_move(object *ob)
Handles a pet&#39;s movement.
Definition: pets.c:329
void pets_remove_all(void)
This function checks all pets so they try to follow their master around the world.
Definition: pets.c:257
Contains information about a race.
Definition: race.h:12
#define FLAG_STAND_STILL
NPC will not (ever) move.
Definition: define.h:309
int pets_summon_object(object *op, object *caster, object *spell_ob, int dir, const char *stringarg)
General purpose summoning function.
Definition: pets.c:935
EXTERN objectlink * first_friendly_object
Objects monsters will go after.
Definition: global.h:123
int pets_summon_golem(object *op, object *caster, int dir, object *spob)
Summons a monster.
Definition: pets.c:672
int attack_ob(object *op, object *hitter)
Simple wrapper for attack_ob_simple(), will use hitter&#39;s values.
Definition: attack.c:903
#define FLAG_FRIENDLY
Will help players.
Definition: define.h:246
object * mon
Definition: comet_perf.c:74
#define MSG_TYPE_SPELL
Spell related info.
Definition: newclient.h:387
uint32_t in_memory
Combination of IN_MEMORY_xxx flags.
Definition: map.h:345
void get_search_arr(int *search_arr)
New function to make monster searching more efficient, and effective! This basically returns a random...
Definition: object.c:3501
#define MSG_TYPE_SPELL_FAILURE
Spell failure messages.
Definition: newclient.h:628
int16_t maxgrace
Maximum grace.
Definition: living.h:44
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.c:280
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
This is basically the same as out_of_map above(), but instead we return NULL if no map is valid (coor...
Definition: map.c:2366
struct treasureliststruct * randomitems
Items to be generated.
Definition: object.h:385
void pets_terminate_all(object *owner)
Removes all pets someone owns.
Definition: pets.c:231
object clone
An object from which to do object_copy()
Definition: object.h:470
int16_t duration
How long the spell lasts.
Definition: object.h:403
int16_t invisible
How much longer the object will be invis.
Definition: object.h:360
short freearr_x[SIZEOFFREE]
X offset when searching around a spot.
Definition: object.c:65
object * monster_check_enemy(object *npc, rv_vector *rv)
Checks npc->enemy and returns that enemy if still valid, NULL otherwise.
Definition: monster.c:71
rangetype shoottype
Which range-attack is being used by player.
Definition: player.h:99
#define DIRX(xyz)
Definition: define.h:477
const char * slaying
Which race to do double damage to.
Definition: object.h:319
#define FLAG_CONFUSED
Will also be unable to cast spells.
Definition: define.h:312
object * ranges[range_size]
Object for each range.
Definition: player.h:103
int SP_level_dam_adjust(const object *caster, const object *spob)
Returns adjusted damage based on the caster.
Definition: spell_util.c:328
int64_t exp
Experience.
Definition: living.h:46
#define object_was_destroyed(op, old_tag)
Checks if an object still exists.
Definition: object.h:68
treasure is one element in a linked list, which together consist of a complete treasure-list.
Definition: treasure.h:63
int freedir[SIZEOFFREE]
Direction we&#39;re pointing on this spot.
Definition: object.c:83
void remove_friendly_object(object *op)
Removes the specified object from the linked list of friendly objects.
Definition: friend.c:56
#define MAX(x, y)
Definition: compat.h:20
void object_update(object *op, int action)
object_update() updates the array which represents the map.
Definition: object.c:1239
int16_t sp
Spell points.
Definition: living.h:41
const object * find_god(const char *name)
Returns pointer to specified god&#39;s object through pntr_to_god_obj().
Definition: gods.c:80
Global type definitions and header inclusions.
#define PETMOVE
If the upper four bits of attack_movement are set to this number, the monster follows a player until ...
Definition: define.h:517
#define safe_strncpy
Definition: compat.h:23
struct obj * enemy
Monster/player to follow even if not closest.
Definition: object.h:381
struct archt * other_arch
Pointer used for various things - mostly used for what this objects turns into or what this object cr...
Definition: object.h:413
int absdir(int d)
Computes an absolute direction.
Definition: object.c:3637
int pets_should_arena_attack(object *pet, object *owner, object *target)
Determines if checks so pets don&#39;t attack players or other pets should be overruled by the arena petm...
Definition: pets.c:1152
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Sends message to player(s).
Definition: main.c:310
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:465
struct archt * item
Which item this link can be.
Definition: treasure.h:64
#define MIN(x, y)
Definition: compat.h:17
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:232
int16_t hp
Hit Points.
Definition: living.h:39
#define DIRY(xyz)
Definition: define.h:478
short freearr_y[SIZEOFFREE]
Y offset when searching around a spot.
Definition: object.c:71
partylist * party
Party this player is part of.
Definition: player.h:186
void create_treasure(treasurelist *t, object *op, int flag, int difficulty, int tries)
This calls the appropriate treasure creation function.
Definition: treasure.c:490
object * ob
Item to link to.
Definition: object.h:443
int rndm(int min, int max)
Returns a number between min and max.
Definition: utils.c:161
void object_set_owner(object *op, object *owner)
Sets the owner and sets the skill and exp pointers to owner&#39;s current skill and experience objects...
Definition: object.c:601
#define MAP_IN_MEMORY
Map is fully loaded.
Definition: map.h:130
struct oblnk * member
Linked object list of things belonging to this race.
Definition: race.h:15
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects, and puts it on the list of free objects.
Definition: object.c:1368
int16_t y
Position in the map for this object.
Definition: object.h:326
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Same as object_insert_in_map() except it handle separate coordinates and do a clean job preparing mul...
Definition: object.c:1921
int16_t maxhp
Max hit points.
Definition: living.h:40
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:230
float speed_left
How much speed is left to spend this round.
Definition: object.h:329
signed short int16_t
Definition: win32.h:160
void pets_move_golem(object *op)
Handles a golem&#39;s movement.
Definition: pets.c:534
racelink * find_racelink(const char *name)
Find the race information for the specified name.
Definition: init.c:1374
int SP_level_wc_adjust(const object *caster, const object *spob)
Returns adjusted wc based on the caster and the spell.
Definition: spell_util.c:403
#define FLAG_UNAGGRESSIVE
Monster doesn&#39;t attack players.
Definition: define.h:272
struct mapdef * map
Pointer to the map in which this object is present.
Definition: object.h:297
void monster_check_apply_all(object *monster)
Calls monster_check_apply() for all inventory objects.
Definition: monster.c:1757
#define snprintf
Definition: win32.h:46
int ob_blocked(const object *ob, mapstruct *m, int16_t x, int16_t y)
Returns true if the given object can&#39;t fit in the given spot.
Definition: map.c:489
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:712
int SP_level_duration_adjust(const object *caster, const object *spob)
Adjust the duration of the spell based on level.
Definition: spell_util.c:353
Control golem.
Definition: player.h:21
int16_t dam
How much damage this object does when hitting.
Definition: living.h:45
int die_roll(int num, int size, const object *op, int goodbad)
Roll a number of dice (2d3, 4d6).
Definition: utils.c:121
void add_friendly_object(object *op)
Add a new friendly object to the linked list of friendly objects.
Definition: friend.c:30
Definition: object.h:145
const char * name
The name of the object, obviously...
Definition: object.h:311
#define FLAG_CHANGING
Changes to other_arch when anim is done.
Definition: define.h:263
struct archt * more
Next part of a linked object.
Definition: object.h:469
int monster_can_detect_enemy(object *op, object *enemy, rv_vector *rv)
Determine if we can &#39;detect&#39; the enemy.
Definition: monster.c:2322
int8_t direction
Means the object is moving that way.
Definition: object.h:334
#define OB_TYPE_MOVE_BLOCK(ob1, type)
Basic macro to see if if ob1 can not move onto a space based on the &#39;type&#39; move_block parameter Add c...
Definition: define.h:447
#define SIZEOFFREE
Definition: define.h:154
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:251
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Gets the blocking state of a square.
Definition: map.h:192
int move_ob(object *op, int dir, object *originator)
Op is trying to move in direction dir.
Definition: move.c:58
struct pl * contr
Pointer to the player which control this object.
Definition: object.h:276
int get_random_dir(void)
Returns a random direction (1..8).
Definition: utils.c:426
int op_on_battleground(object *op, int *x, int *y, archetype **trophy)
Check if the given object (usually a player) is standing on a battleground tile.
Definition: player.c:4232
#define FREE_AND_CLEAR_STR(xyz)
Release the shared string, and set it to NULL.
Definition: global.h:208
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:12
#define AT_PHYSICAL
Definition: attack.h:76
float speed
The overall speed of this object.
Definition: object.h:328
int on_same_map(const object *op1, const object *op2)
Checks whether 2 objects are on the same map or not.
Definition: map.c:2627
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
#define CLEAR_FLAG(xyz, p)
Definition: define.h:224
#define HEAD(op)
Returns the head part of an object.
Definition: object.h:594
uint32_t golem_count
To track the golem.
Definition: player.h:106
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
uint16_t nrof
random 1 to nrof items are generated
Definition: treasure.h:76
Many many details.
Definition: logger.h:14
int16_t x
Definition: object.h:326
struct treasurestruct * items
Items in this list, linked.
Definition: treasure.h:90
int8_t wc
Weapon Class, how skilled, the lower the better.
Definition: living.h:36
#define AT_DRAIN
Definition: attack.h:83
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:765
int16_t resist[NROFATTACKS]
Resistance adjustments for attacks.
Definition: object.h:341
See Player.
Definition: object.h:107
const char * name
Usually monster-name/combination.
Definition: treasure.h:83
#define PREFER_HIGH
Definition: define.h:599
uint32_t attacktype
Bitmask of attacks this object does.
Definition: object.h:342
#define FLAG_GENERATOR
Will generate type ob->stats.food.
Definition: define.h:248
#define RANDOM()
Definition: define.h:679
archetype * determine_holy_arch(const object *god, const char *type)
Determines the archetype for holy servant and god avatar.
Definition: gods.c:735
int SP_level_range_adjust(const object *caster, const object *spob)
Adjust the range of the spell based on level.
Definition: spell_util.c:379
#define MSG_TYPE_SPELL_PET
Pet related messages.
Definition: newclient.h:627
tag_t count
Unique object number for this object.
Definition: object.h:299
living stats
Str, Con, Dex, etc.
Definition: object.h:368
struct archt * arch
Pointer to archetype.
Definition: object.h:412
void set_spell_skill(object *op, object *caster, object *spob, object *dest)
Utility function to assign the correct skill when casting.
Definition: spell_util.c:94
struct oblnk * next
Next item to link to.
Definition: object.h:444
Only for debugging purposes.
Definition: logger.h:13
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:338
void object_set_enemy(object *op, object *enemy)
Sets the enemy of an object.
Definition: object.c:679
Generated items have the FLAG_STARTEQUIP.
Definition: treasure.h:33
int direction
General direction to the targer.
Definition: map.h:384
#define FLAG_SPLITTING
Object splits into stats.food other objs.
Definition: define.h:266
static object * get_real_owner(object *ob)
Recursively look through the owner property of objects until the real owner is found.
Definition: pets.c:1122
const char * msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:322
void pets_follow_owner(object *ob, object *owner)
A pet is trying to follow its owner.
Definition: pets.c:293
sstring add_string(const char *str)
This will add &#39;str&#39; to the hash table.
Definition: shstr.c:124
#define MIN_ACTIVE_SPEED
Cut off point of when an object is put on the active list or not.
Definition: define.h:674
#define FLAG_MONSTER
Will attack players.
Definition: define.h:245
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
This rolls up wall, blocks_magic, blocks_view, etc, all into one function that just returns a P_...
Definition: map.c:302
petmode_t petmode
Which petmode?
Definition: player.h:102
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:245
#define SIZEOFFREE1
Definition: define.h:152
struct obj * head
Points to the main object of a large body.
Definition: object.h:296
#define MSG_SUBTYPE_NONE
Definition: newclient.h:398
Try to find enemies.
Definition: player.h:46
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.c:51
void pets_control_golem(object *op, int dir)
Makes the golem go in specified direction.
Definition: pets.c:648
static object * choose_cult_monster(object *pl, const object *god, int summon_level)
Returns a monster (chosen at random) that this particular player (and his god) find acceptable...
Definition: pets.c:840
Stay close to the owner.
Definition: player.h:47
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:758
int object_find_free_spot(const object *ob, mapstruct *m, int x, int y, int start, int stop)
object_find_free_spot(object, map, x, y, start, stop) will search for a spot at the given map and coo...
Definition: object.c:3415
This is a game-map.
Definition: map.h:325
#define P_IS_ALIVE
Something alive is on this space.
Definition: map.h:237
int random_roll(int min, int max, const object *op, int goodbad)
Roll a random number between min and max.
Definition: utils.c:42
static object * fix_summon_pet(archetype *at, object *op, int dir)
This makes multisquare/single square monsters proper for map insertion.
Definition: pets.c:446
int get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags)
From map.c This is used by get_player to determine where the other creature is.
Definition: map.c:2516
struct treasurestruct * next
Next treasure-item in a linked list.
Definition: treasure.h:66
object * monster_find_nearest_living_creature(object *npc)
Returns the nearest living creature (monster or generator).
Definition: monster.c:152
int16_t level
Level of creature or object.
Definition: object.h:351
struct obj * more
Pointer to the rest of a large body of objects.
Definition: object.h:295
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.c:571
object * object_get_owner(object *op)
Returns the object which this object marks as being the owner.
Definition: object.c:559
const char * name
More definite name, like "generate_kobold".
Definition: object.h:466
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:705
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to...
Definition: object.c:1654
struct obj * attacked_by
This object start to attack us! only player & monster.
Definition: object.h:382
object * pets_get_enemy(object *pet, rv_vector *rv)
Given that &#39;pet&#39; is a friendly object, this function returns a monster the pet should attack...
Definition: pets.c:57