Crossfire Server  1.75.0
pets.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 
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 
54 object *pets_get_enemy(object *pet, rv_vector *rv) {
55  object *owner, *tmp, *attacker, *tmp3;
56  int i;
57  int16_t x, y;
58  mapstruct *nm;
59  int search_arr[SIZEOFFREE];
60  int mflags;
61 
62  attacker = pet->attacked_by; /*pointer to attacking enemy*/
63  pet->attacked_by = NULL; /*clear this, since we are dealing with it*/
64 
65  owner = object_get_owner(pet);
66  if (owner != NULL) {
67  /* If the owner has turned on the pet, make the pet
68  * unfriendly.
69  */
70  if (monster_check_enemy(owner, rv) == pet) {
73  pet->attack_movement &= ~PETMOVE;
74  return owner;
75  }
76  } else {
77  /* else the owner is no longer around, so the
78  * pet no longer needs to be friendly.
79  */
82  pet->attack_movement &= ~PETMOVE;
83  return NULL;
84  }
85  /* If they are not on the same map, the pet won't be agressive */
86  if (!on_same_map(pet, owner))
87  return NULL;
88 
89  /* See if the pet has an existing enemy. If so, don't start a new one*/
90  tmp = monster_check_enemy(pet, rv);
91  if (tmp != NULL) {
92  if (tmp != owner || QUERY_FLAG(pet, FLAG_CONFUSED) || !QUERY_FLAG(pet, FLAG_FRIENDLY))
93  return tmp;
94 
95  /* without this check, you can actually get pets with
96  * enemy set to owner!
97  */
98  object_set_enemy(pet, NULL);
99  }
100  get_search_arr(search_arr);
101 
102  if (owner->type == PLAYER && owner->contr->petmode == pet_sad) {
103  tmp = monster_find_nearest_enemy(pet, owner);
104  if (tmp != NULL && get_rangevector(pet, tmp, rv, 0))
105  return tmp;
106  /* if we got here we still have no enemy */
107  /* we return NULL to avoid heading back to the owner */
108  object_set_enemy(pet, NULL);
109  return NULL;
110  }
111 
112  /* Since the pet has no existing enemy, look for anything nasty
113  * around the owner that it should go and attack.
114  */
115  tmp3 = NULL;
116  for (i = 0; i < SIZEOFFREE; i++) {
117  x = owner->x+freearr_x[search_arr[i]];
118  y = owner->y+freearr_y[search_arr[i]];
119  nm = owner->map;
120  /* Only look on the space if there is something alive there. */
121  mflags = get_map_flags(nm, &nm, x, y, &x, &y);
122  if (!(mflags&P_OUT_OF_MAP) && mflags&P_IS_ALIVE) {
123  FOR_MAP_PREPARE(nm, x, y, tmp) {
124  object *tmp2 = HEAD(tmp);
125 
126  if (QUERY_FLAG(tmp2, FLAG_ALIVE)
127  && ((!QUERY_FLAG(tmp2, FLAG_FRIENDLY) && tmp2->type != PLAYER) || pets_should_arena_attack(pet, owner, tmp2))
128  && !QUERY_FLAG(tmp2, FLAG_UNAGGRESSIVE)
129  && tmp2 != pet
130  && tmp2 != owner
131  && monster_can_detect_enemy(pet, tmp2, rv)) {
132  if (!monster_can_see_enemy(pet, tmp2)) {
133  if (tmp3 == NULL)
134  tmp3 = tmp2;
135  } else {
136  object_set_enemy(pet, tmp2);
137  if (monster_check_enemy(pet, rv) != NULL)
138  return tmp2;
139  object_set_enemy(pet, NULL);
140  }
141  }/* if this is a valid enemy */
142  } FOR_MAP_FINISH();/* for objects on this space */
143  }/* if there is something living on this space */
144  } /* for loop of spaces around the owner */
145 
146  /* fine, we went through the whole loop and didn't find one we could
147  see, take what we have */
148  if (tmp3 != NULL) {
149  object_set_enemy(pet, tmp3);
150  if (monster_check_enemy(pet, rv) != NULL)
151  return tmp3;
152  object_set_enemy(pet, NULL);
153  }
154 
155  /* No threat to owner, check to see if the pet has an attacker*/
156  if (attacker != NULL) {
157  /* need to be sure this is the right one! */
158  if (attacker->count == pet->attacked_by_count) {
159  /* also need to check to make sure it is not freindly */
160  /* or otherwise non-hostile, and is an appropriate target */
161  if (!QUERY_FLAG(attacker, FLAG_FRIENDLY) && on_same_map(pet, attacker)) {
162  object_set_enemy(pet, attacker);
163  if (monster_check_enemy(pet, rv) != NULL)
164  return attacker;
165  object_set_enemy(pet, NULL);
166  }
167  }
168  }
169 
170  /* Don't have an attacker or legal enemy, so look for a new one!.
171  * This looks for one around where the pet is. Thus, you could lead
172  * a pet to danger, then take a few steps back. This code is basically
173  * the same as the code that looks around the owner.
174  */
175  if (owner->type == PLAYER && owner->contr->petmode != pet_defend) {
176  tmp3 = NULL;
177  for (i = 0; i < SIZEOFFREE; i++) {
178  x = pet->x+freearr_x[search_arr[i]];
179  y = pet->y+freearr_y[search_arr[i]];
180  nm = pet->map;
181  /* Only look on the space if there is something alive there. */
182  mflags = get_map_flags(nm, &nm, x, y, &x, &y);
183  if (!(mflags&P_OUT_OF_MAP) && mflags&P_IS_ALIVE) {
184  FOR_MAP_PREPARE(nm, x, y, tmp) {
185  object *tmp2 = HEAD(tmp);
186  if (QUERY_FLAG(tmp2, FLAG_ALIVE)
187  && ((!QUERY_FLAG(tmp2, FLAG_FRIENDLY) && tmp2->type != PLAYER) || pets_should_arena_attack(pet, owner, tmp2))
188  && !QUERY_FLAG(tmp2, FLAG_UNAGGRESSIVE)
189  && tmp2 != pet
190  && tmp2 != owner
191  && monster_can_detect_enemy(pet, tmp2, rv)) {
192  if (!monster_can_see_enemy(pet, tmp2)) {
193  assert(tmp3 == NULL);
194  } else {
195  object_set_enemy(pet, tmp2);
196  if (monster_check_enemy(pet, rv) != NULL)
197  return tmp2;
198  object_set_enemy(pet, NULL);
199  }
200  } /* make sure we can get to the bugger */
201  } FOR_MAP_FINISH();/* for objects on this space */
202  } /* if there is something living on this space */
203  } /* for loop of spaces around the pet */
204  } /* pet in defence mode */
205 
206  /* fine, we went through the whole loop and didn't find one we could
207  see, take what we have */
208  if (tmp3 != NULL) {
209  object_set_enemy(pet, tmp3);
210  if (monster_check_enemy(pet, rv) != NULL)
211  return tmp3;
212  object_set_enemy(pet, NULL);
213  }
214 
215  /* Didn't find anything - return the owner's enemy or NULL */
216  return monster_check_enemy(pet, rv);
217 }
218 
224 void pets_terminate(object *pet)
225 {
226  if (pet->owner && pet->owner->contr && pet->owner->contr->ranges[range_golem] == pet) {
227  pet->owner->contr->ranges[range_golem] = nullptr;
228  pet->owner->contr->golem_count = 0;
229  }
230  if (!QUERY_FLAG(pet, FLAG_REMOVED))
231  object_remove(pet);
234 }
235 
242 void pets_terminate_all(object *owner) {
243  objectlink *link = get_friends_of(owner), *cur;
244  if (!link) {
245  return;
246  }
247  for (cur = link; cur != NULL; cur = cur->next) {
248  pets_terminate(cur->ob);
249  }
250 
251  free_objectlink(link);
252 }
253 
262 void pets_attempt_follow(object *for_owner, int force) {
263  objectlink *list = get_friends_of(for_owner), *cur;
264  object *owner;
265  if (!list) {
266  return;
267  }
268 
269  for (cur = list; cur != NULL; cur = cur->next) {
270  if (cur->ob->type != PLAYER
271  && QUERY_FLAG(cur->ob, FLAG_FRIENDLY)
272  && (owner = object_get_owner(cur->ob)) != NULL
273  && (for_owner == NULL || for_owner == owner)
274  && (force || !on_same_map(owner, cur->ob))) {
275  /* follow owner checks map status for us. Note that pet can
276  * die in pets_follow_owner(), so check for obl->ob existence
277  */
278  pets_follow_owner(cur->ob, owner);
279  if (cur->ob && QUERY_FLAG(cur->ob, FLAG_REMOVED) && FABS(cur->ob->speed) > MIN_ACTIVE_SPEED) {
280  LOG(llevMonster, "(pet failed to follow)\n");
281  remove_friendly_object(cur->ob);
283  }
284  }
285  }
286  free_objectlink(list);
287 }
288 
297 void pets_follow_owner(object *ob, object *owner) {
298  int dir;
299 
300  if (!QUERY_FLAG(ob, FLAG_REMOVED))
301  object_remove(ob);
302 
303  if (owner->map == NULL) {
304  LOG(llevError, "Can't follow owner: no map.\n");
305  return;
306  }
307  if (owner->map->in_memory != MAP_IN_MEMORY) {
308  LOG(llevError, "Owner of the pet not on a map in memory!?\n");
309  return;
310  }
311  dir = object_find_free_spot(ob, owner->map, owner->x, owner->y, 1, SIZEOFFREE);
312 
313  if (dir == -1) {
314  LOG(llevMonster, "No space for pet to follow, freeing %s.\n", ob->name);
315  return; /* Will be freed since it's removed */
316  }
317  object_insert_in_map_at(ob, owner->map, NULL, 0, owner->x+freearr_x[dir], owner->y+freearr_y[dir]);
318  if (owner->type == PLAYER) /* Uh, I hope this is always true... */
320  "Your pet magically appears next to you");
321  return;
322 }
323 
330 void pets_move(object *ob) {
331  int dir, i;
332  tag_t tag;
333  int16_t dx, dy;
334  object *owner;
335  mapstruct *m;
336 
337  /* Check to see if player pulled out */
338  owner = object_get_owner(ob);
339  if (owner == NULL) {
340  object_remove(ob); /* Will be freed when returning */
343  LOG(llevMonster, "Pet: no owner, leaving.\n");
344  return;
345  }
346 
347  /* move monster into the owners map if not in the same map */
348  if (!on_same_map(ob, owner)) {
349  pets_follow_owner(ob, owner);
350  return;
351  }
352  /* Calculate Direction */
353  if (owner->type == PLAYER && owner->contr->petmode == pet_sad) {
354  /* in S&D mode, if we have no enemy, run randomly about. */
355  for (i = 0; i < 15; i++) {
356  dir = get_random_dir();
357  dx = ob->x+freearr_x[dir];
358  dy = ob->y+freearr_y[dir];
359  m = ob->map;
360  if (!(get_map_flags(ob->map, &m, dx, dy, &dx, &dy)&P_OUT_OF_MAP)
361  && !OB_TYPE_MOVE_BLOCK(ob, GET_MAP_MOVE_BLOCK(m, dx, dy)))
362  break;
363  }
364  } else {
365  rv_vector rv;
366 
367  if (get_rangevector(ob, owner, &rv, 0))
368  dir = rv.direction;
369  else
370  dir = get_random_dir();
371  }
372  ob->direction = dir;
373 
374  tag = ob->count;
375  /* move_ob returns 0 if the object couldn't move. If that is the
376  * case, lets do some other work.
377  */
378  if (!move_ob(ob, dir, ob)) {
379  object *part;
380 
381  /* the failed move_ob above may destroy the pet, so check here */
382  if (object_was_destroyed(ob, tag))
383  return;
384 
385  for (part = ob; part != NULL; part = part->more) {
386  dx = part->x+freearr_x[dir];
387  dy = part->y+freearr_y[dir];
388  m = get_map_from_coord(part->map, &dx, &dy);
389  if (m == NULL)
390  continue;
391 
392  FOR_MAP_PREPARE(m, dx, dy, ob2) {
393  object *new_ob;
394 
395  new_ob = HEAD(ob2);
396  if (new_ob == ob)
397  break;
398  if (new_ob == owner)
399  return;
400  if (object_get_owner(new_ob) == owner)
401  break;
402 
403  /* Hmm. Did we try to move into an enemy monster? If so,
404  * make it our enemy.
405  */
406  if (QUERY_FLAG(new_ob, FLAG_ALIVE)
408  && !QUERY_FLAG(new_ob, FLAG_UNAGGRESSIVE)
409  && !QUERY_FLAG(new_ob, FLAG_FRIENDLY)) {
410  object_set_enemy(ob, new_ob);
411  if (new_ob->enemy == NULL)
412  object_set_enemy(new_ob, ob);
413  return;
414  } else if (new_ob->type == PLAYER) {
415  draw_ext_info(NDI_UNIQUE, 0, new_ob,
417  "You stand in the way of someones pet.");
418  return;
419  }
420  } FOR_MAP_FINISH();
421  }
422  /* Try a different course */
423  dir = absdir(dir+4-(RANDOM()%5)-(RANDOM()%5));
424  (void)move_ob(ob, dir, ob);
425  }
426  return;
427 }
428 
429 /****************************************************************************
430  *
431  * GOLEM SPELL CODE
432  *
433  ****************************************************************************/
434 
447 static object *fix_summon_pet(archetype *at, object *op, int dir) {
448  archetype *atmp;
449  object *tmp = NULL, *prev = NULL, *head = NULL;
450 
451  for (atmp = at; atmp != NULL; atmp = atmp->more) {
452  tmp = arch_to_object(atmp);
453  if (atmp == at) {
454 
455  /* Ensure the golem can actually move if no move_type defined.
456  * This check is redundant since this is checked at server startup. */
457  if (tmp->move_type == 0) {
458  LOG(llevError, "summoned %s [%s] is without move_type!\n", tmp->name, atmp->name);
459  tmp->move_type = MOVE_WALK;
460  }
461 
462  object_set_owner(tmp, op);
463  if (op->type == PLAYER) {
464  tmp->stats.exp = 0;
465  add_friendly_object(tmp);
466  SET_FLAG(tmp, FLAG_FRIENDLY);
467  CLEAR_FLAG(tmp, FLAG_MONSTER);
468  } else if (QUERY_FLAG(op, FLAG_FRIENDLY)) {
469  object *owner = object_get_owner(op);
470 
471  if (owner != NULL) {/* For now, we transfer ownership */
472  object_set_owner(tmp, owner);
473  tmp->attack_movement = PETMOVE;
474  add_friendly_object(tmp);
475  SET_FLAG(tmp, FLAG_FRIENDLY);
476  }
477  }
478  if (op->type != PLAYER) {
479  tmp->attack_movement = PETMOVE;
480  tmp->speed_left = -1;
481  tmp->type = 0;
482  object_set_enemy(tmp, op->enemy);
483  } else
484  tmp->type = GOLEM;
485  }
486  if (head == NULL)
487  head = tmp;
488  tmp->x = op->x+freearr_x[dir]+tmp->arch->clone.x;
489  tmp->y = op->y+freearr_y[dir]+tmp->arch->clone.y;
490  tmp->map = op->map;
491  if (tmp->invisible)
492  tmp->invisible = 0;
493  if (head != tmp)
494  tmp->head = head,
495  prev->more = tmp;
496  prev = tmp;
497  }
498  head->direction = dir;
499 
500  if (head->randomitems) {
501  create_treasure(head->randomitems, head, GT_STARTEQUIP, 6, 0);
502  if (QUERY_FLAG(head, FLAG_MONSTER)) {
504  }
505  }
507 
508  /* need to change some monster attr to prevent problems/crashing */
509  head->last_heal = 0;
510  head->last_eat = 0;
511  head->last_grace = 0;
512  head->last_sp = 0;
513  head->other_arch = NULL;
514  head->stats.exp = 0;
515  CLEAR_FLAG(head, FLAG_CHANGING);
517  CLEAR_FLAG(head, FLAG_GENERATOR);
518  CLEAR_FLAG(head, FLAG_SPLITTING);
519  if (head->attacktype&AT_GHOSTHIT)
520  head->attacktype = (AT_PHYSICAL|AT_DRAIN);
521 
522  return head;
523 }
524 
532 void pets_move_golem(object *op) {
533  int made_attack = 0;
534  object *tmp;
535  tag_t tag;
536  object *owner;
537 
538  if (QUERY_FLAG(op, FLAG_MONSTER))
539  return; /* Has already been moved */
540 
541  owner = object_get_owner(op);
542  if (owner == NULL) {
543  LOG(llevDebug, "Golem without owner destructed.\n");
544  object_remove(op);
546  return;
547  }
548  /* It would be nice to have a cleaner way of what message to print
549  * when the golem expires than these hard coded entries.
550  * Note it is intentional that a golems duration is based on its
551  * hp, and not duration
552  */
553  if (--op->stats.hp < 0) {
554  if (op->msg != NULL)
556  op->msg);
557  owner->contr->ranges[range_golem] = NULL;
558  owner->contr->golem_count = 0;
560  object_remove(op);
562  return;
563  }
564 
565  /* Do golem attacks/movement for single & multisq golems.
566  * Assuming here that op is the 'head' object. Pass only op to
567  * move_ob (makes recursive calls to other parts)
568  * move_ob returns 0 if the creature was not able to move.
569  */
570  tag = op->count;
571  if (move_ob(op, op->direction, op))
572  return;
573  if (object_was_destroyed(op, tag))
574  return;
575 
576  for (tmp = op; tmp; tmp = tmp->more) {
577  int16_t x = tmp->x+DIRX(op), y = tmp->y+DIRY(op);
578  object *victim;
579  mapstruct *m;
580  int mflags;
581 
582  m = op->map;
583  mflags = get_map_flags(m, &m, x, y, &x, &y);
584 
585  if (mflags&P_OUT_OF_MAP)
586  continue;
587 
588  victim = NULL;
589  FOR_MAP_PREPARE(op->map, x, y, tmp)
590  if (QUERY_FLAG(tmp, FLAG_ALIVE)) {
591  victim = tmp;
592  break;
593  }
594  FOR_MAP_FINISH();
595 
596  /* We used to call will_hit_self to make sure we don't
597  * hit ourselves, but that didn't work, and I don't really
598  * know if that was more efficient anyways than this.
599  * This at least works. Note that victim->head can be NULL,
600  * but since we are not trying to dereferance that pointer,
601  * that isn't a problem.
602  */
603  if (victim != NULL && victim != op && victim->head != op) {
604  /* for golems with race fields, we don't attack
605  * aligned races
606  */
607 
608  if (victim->race != NULL && op->race != NULL && strstr(op->race, victim->race)) {
609  if (owner != NULL)
612  "%s avoids damaging %s.",
613  op->name, victim->name);
614  } else if (victim == owner) {
615  if (owner != NULL)
618  "%s avoids damaging you.",
619  op->name);
620  } else {
621  attack_ob(victim, op);
622  made_attack = 1;
623  }
624  } /* If victim */
625  }
626  if (made_attack)
628 }
629 
643 void pets_control_golem(object *op, int dir) {
644  op->direction = dir;
645 }
646 
664 int pets_summon_golem(object *op, object *caster, int dir, object *spob) {
665  object *tmp;
666  const object *god = NULL;
667  archetype *at;
668  char buf[MAX_BUF];
669 
670  /* Because there can be different golem spells, player may want to
671  * 'lose' their old golem.
672  */
673  if (op->type == PLAYER
674  && op->contr->ranges[range_golem] != NULL
675  && op->contr->golem_count == op->contr->ranges[range_golem]->count) {
676  draw_ext_info(NDI_UNIQUE, 0, op,
678  "You dismiss your existing golem.");
681  op->contr->ranges[range_golem] = NULL;
682  op->contr->golem_count = -1;
683  }
684 
685  if (spob->other_arch != NULL)
686  at = spob->other_arch;
687  else if (spob->race != NULL) {
688  god = find_god(determine_god(caster));
689  if (god == NULL) {
692  "You must worship a god to cast %s.",
693  spob->name);
694  return 0;
695  }
696 
697  at = determine_holy_arch(god, spob->race);
698  if (at == NULL) {
701  "%s has no %s for you to call.",
702  god->name, spob->race);
703  return 0;
704  }
705  } else {
706  LOG(llevError, "Spell %s lacks other_arch\n", spob->name);
707  return 0;
708  }
709 
710  if (!dir)
711  dir = object_find_free_spot(NULL, op->map, op->x, op->y, 1, SIZEOFFREE1+1);
712 
713  if (dir == -1
714  || ob_blocked(&at->clone, op->map, op->x+freearr_x[dir], op->y+freearr_y[dir])) {
715  draw_ext_info(NDI_UNIQUE, 0, op,
717  "There is something in the way.");
718  return 0;
719  }
720  /* basically want to get proper map/coordinates for this object */
721  tmp = fix_summon_pet(at, op, dir);
722  if (tmp == NULL) {
723  draw_ext_info(NDI_UNIQUE, 0, op,
725  "Your spell fails.");
726  return 0;
727  }
728 
729  if (op->type == PLAYER) {
730  tmp->type = GOLEM;
731  object_set_owner(tmp, op);
732  set_spell_skill(op, caster, spob, tmp);
733  op->contr->ranges[range_golem] = tmp;
734  op->contr->golem_count = tmp->count;
735  /* give the player control of the golem */
736  op->contr->shoottype = range_golem;
737  } else {
738  if (QUERY_FLAG(op, FLAG_FRIENDLY)) {
739  object *owner = object_get_owner(op);
740 
741  if (owner != NULL) { /* For now, we transfer ownership */
742  object_set_owner(tmp, owner);
743  tmp->attack_movement = PETMOVE;
744  add_friendly_object(tmp);
745  set_spell_skill(op, caster, spob, tmp);
746  SET_FLAG(tmp, FLAG_FRIENDLY);
747  }
748  }
749  SET_FLAG(tmp, FLAG_MONSTER);
750  }
751 
752  /* make the speed positive.*/
753  tmp->speed = FABS(tmp->speed);
754 
755  /* This sets the level dependencies on dam and hp for monsters */
756  /* players can't cope with too strong summonings. */
757  /* but monsters can. reserve these for players. */
758  if (op->type == PLAYER) {
759  tmp->stats.hp += spob->duration+SP_level_duration_adjust(caster, spob);
760  tmp->stats.maxhp = tmp->stats.hp;
761  if (!spob->stats.dam)
762  tmp->stats.dam += SP_level_dam_adjust(caster, spob);
763  else
764  tmp->stats.dam = spob->stats.dam+SP_level_dam_adjust(caster, spob);
765  tmp->speed += .02*SP_level_range_adjust(caster, spob);
766  tmp->speed = MIN(tmp->speed, 1.0);
767  if (spob->attacktype)
768  tmp->attacktype = spob->attacktype;
769  }
770  tmp->stats.wc -= SP_level_wc_adjust(caster, spob);
771 
772  /* limit the speed to 0.3 for non-players, 1 for players. */
773 
774  /* make experience increase in proportion to the strength.
775  * this is a bit simplistic - we are basically just looking at how
776  * often the sp doubles and use that as the ratio.
777  */
778  tmp->stats.exp *= 1+(MAX(spob->stats.maxgrace, spob->stats.sp)/caster_level(caster, spob));
779  tmp->speed_left = 0;
780  tmp->direction = dir;
781 
782  /* Holy spell - some additional tailoring */
783  if (god != NULL) {
784  object *tmp2;
785 
786  snprintf(buf, sizeof(buf), "%s of %s", spob->name, god->name);
787  buf[0] = toupper(buf[0]);
788  for (tmp2 = tmp; tmp2; tmp2 = tmp2->more) {
789  if (tmp2->name != NULL)
790  free_string(tmp2->name);
791  tmp2->name = add_string(buf);
792  }
793  tmp->attacktype |= god->attacktype;
794  memcpy(tmp->resist, god->resist, sizeof(tmp->resist));
795  if (tmp->race != NULL)
796  FREE_AND_CLEAR_STR(tmp->race);
797  if (god->race != NULL)
798  tmp->race = add_string(god->race);
799  if (tmp->slaying != NULL)
801  if (god->slaying != NULL)
802  tmp->slaying = add_string(god->slaying);
803  /* safety, we must allow a god's servants some reasonable attack */
804  if (!(tmp->attacktype&AT_PHYSICAL))
805  tmp->attacktype |= AT_PHYSICAL;
806  }
807 
808  object_insert_in_map_at(tmp, tmp->map, op, 0, tmp->x, tmp->y);
809  return 1;
810 }
811 
812 /***************************************************************************
813  *
814  * Summon monster/pet/other object code
815  *
816  ***************************************************************************/
817 
832 static object *choose_cult_monster(object *pl, const object *god, int summon_level) {
833  char buf[MAX_BUF];
834  const char *race;
835  int racenr, i;
836  object *otmp;
837 
838  /* Determine the number of races available */
839  racenr = 0;
840  safe_strncpy(buf, god->race, sizeof(buf));
841  race = strtok(buf, ",");
842  while (race) {
843  racenr++;
844  race = strtok(NULL, ",");
845  }
846 
847  /* next, randomly select a race from the aligned_races string */
848  if (racenr > 1) {
849  racenr = rndm(0, racenr-1);
850  safe_strncpy(buf, god->race, sizeof(buf));
851  race = strtok(buf, ",");
852  for (i = 0; i < racenr; i++)
853  race = strtok(NULL, ",");
854  } else
855  race = god->race;
856 
857  otmp = races_get_random_monster(race, summon_level);
858  if (!otmp) {
861  "The spell fails! %s's creatures are beyond the range of your summons",
862  god->name);
863  }
864  return otmp;
865 }
866 
885 int pets_summon_object(object *op, object *caster, object *spell_ob, int dir, const char *stringarg) {
886  int16_t x, y, nrof = 1, i;
887  archetype *summon_arch;
888  int ndir, mult;
889 
890  if (spell_ob->other_arch != NULL) {
891  summon_arch = spell_ob->other_arch;
892  } else if (spell_ob->randomitems != NULL) {
893  int level = caster_level(caster, spell_ob);
894  treasure *tr, *lasttr = NULL;
895 
896  /* In old code, this was a very convuluted for statement,
897  * with all the checks in the 'for' portion itself. Much
898  * more readable to break some of the conditions out.
899  */
900  for (tr = spell_ob->randomitems->items; tr; tr = tr->next) {
901  if (level < tr->magic)
902  break;
903  lasttr = tr;
904  if (stringarg != NULL && !strcmp(tr->item->name, stringarg))
905  break;
906  if (tr->next == NULL || tr->next->item == NULL)
907  break;
908  }
909  if (lasttr == NULL) {
910  LOG(llevError, "Treasurelist %s did not generate a valid entry in pets_summon_object\n", spell_ob->randomitems->name);
911  draw_ext_info(NDI_UNIQUE, 0, op,
913  "The spell fails to summon any monsters.");
914  return 0;
915  }
916  summon_arch = lasttr->item;
917  nrof = lasttr->nrof;
918  } else if (spell_ob->race != NULL && !strcmp(spell_ob->race, "GODCULTMON")) {
919  const object *god = find_god(determine_god(op));
920  object *mon, *owner;
921  int summon_level, tries;
922 
923  if (god == NULL) {
924  owner = object_get_owner(op);
925  if (owner != NULL) {
926  god = find_god(determine_god(owner));
927  }
928  }
929  /* If we can't find a god, can't get what monster to summon */
930  if (god == NULL)
931  return 0;
932 
933  if (god->race == NULL) {
936  "%s has no creatures that you may summon!",
937  god->name);
938  return 0;
939  }
940  /* the summon level */
941  summon_level = caster_level(caster, spell_ob);
942  if (summon_level == 0)
943  summon_level = 1;
944  tries = 0;
945  do {
946  mon = choose_cult_monster(op, god, summon_level);
947  if (mon == NULL) {
950  "%s fails to send anything.",
951  god->name);
952  return 0;
953  }
954  ndir = dir;
955  if (!ndir)
956  ndir = object_find_free_spot(mon, op->map, op->x, op->y, 1, SIZEOFFREE);
957  if (ndir == -1
958  || ob_blocked(mon, op->map, op->x+freearr_x[ndir], op->y+freearr_y[ndir])) {
959  ndir = -1;
960  if (++tries == 5) {
961  draw_ext_info(NDI_UNIQUE, 0, op,
963  "There is something in the way.");
964  return 0;
965  }
966  }
967  } while (ndir == -1);
968  if (mon->level > summon_level/2)
969  nrof = random_roll(1, 2, op, PREFER_HIGH);
970  else
971  nrof = die_roll(2, 2, op, PREFER_HIGH);
972  summon_arch = mon->arch;
973  } else {
974  summon_arch = NULL;
975  }
976 
977  if (spell_ob->stats.dam)
978  nrof += spell_ob->stats.dam+SP_level_dam_adjust(caster, spell_ob);
979 
980  if (summon_arch == NULL) {
982  "There is no monsters available for summoning.");
983  return 0;
984  }
985 
986  if (dir) {
987  /* Only fail if caster specified a blocked direction. */
988  x = freearr_x[dir];
989  y = freearr_y[dir];
990  if (ob_blocked(&summon_arch->clone, op->map, op->x+x, op->y+y)) {
992  "There is something in the way.");
993  return 0;
994  }
995  }
996 
997  mult = (RANDOM()%2 ? -1 : 1);
998 
999  for (i = 1; i <= nrof; i++) {
1000  archetype *atmp;
1001  object *prev = NULL, *head = NULL, *tmp;
1002 
1003  if (dir) {
1004  ndir = absdir(dir+(i/2)*mult);
1005  mult = -mult;
1006  } else
1007  ndir = object_find_free_spot(&summon_arch->clone, op->map, op->x, op->y, 1, SIZEOFFREE);
1008 
1009  x = ndir > 0 ? freearr_x[ndir] : 0;
1010  y = ndir > 0 ? freearr_y[ndir] : 0;
1011  if (ndir == -1 || ob_blocked(&summon_arch->clone, op->map, op->x+x, op->y+y))
1012  continue;
1013 
1014  for (atmp = summon_arch; atmp != NULL; atmp = atmp->more) {
1015  tmp = arch_to_object(atmp);
1016  if (atmp == summon_arch) {
1017  if (QUERY_FLAG(tmp, FLAG_MONSTER)) {
1018  object_set_owner(tmp, op);
1019  set_spell_skill(op, caster, spell_ob, tmp);
1020  object_set_enemy(tmp, op->enemy);
1021  tmp->type = 0;
1022  CLEAR_FLAG(tmp, FLAG_SLEEP);
1023  if (op->type == PLAYER || QUERY_FLAG(op, FLAG_FRIENDLY)) {
1024  /* If this is not set, we make it friendly */
1025  if (!QUERY_FLAG(spell_ob, FLAG_MONSTER)) {
1026  SET_FLAG(tmp, FLAG_FRIENDLY);
1027  add_friendly_object(tmp);
1028  tmp->stats.exp = 0;
1029  if (spell_ob->attack_movement)
1030  tmp->attack_movement = spell_ob->attack_movement;
1031  if (object_get_owner(op) != NULL)
1033  }
1034  }
1035  }
1036  if (tmp->speed > MIN_ACTIVE_SPEED)
1037  tmp->speed_left = -1;
1038  }
1039  if (head == NULL)
1040  head = tmp;
1041  else {
1042  tmp->head = head;
1043  prev->more = tmp;
1044  }
1045  prev = tmp;
1046  }
1047  head->direction = freedir[ndir];
1048  head->stats.exp = 0;
1049  head = object_insert_in_map_at(head, op->map, op, 0, op->x+x, op->y+y);
1050  if (head != NULL && head->randomitems) {
1051  create_treasure(head->randomitems, head, GT_STARTEQUIP, 6, 0);
1052  if (QUERY_FLAG(head, FLAG_MONSTER)) {
1054  }
1055  }
1056  if (head != NULL) {
1058  }
1059  } /* for i < nrof */
1060  return 1;
1061 }
1062 
1072 static object *get_real_owner(object *ob) {
1073  object *realowner = ob;
1074 
1075  if (realowner == NULL)
1076  return NULL;
1077 
1078  while (object_get_owner(realowner) != NULL) {
1079  realowner = object_get_owner(realowner);
1080  }
1081  return realowner;
1082 }
1083 
1099 int pets_should_arena_attack(object *pet, object *owner, object *target) {
1100  object *rowner, *towner;
1101 
1102  /* exit if the target, pet, or owner is null. */
1103  if (target == NULL || pet == NULL || owner == NULL)
1104  return 0;
1105 
1106  /* get the owners of itself and the target, this is to deal with pets of
1107  pets */
1108  rowner = get_real_owner(owner);
1109  if (target->type != PLAYER) {
1110  towner = get_real_owner(target);
1111  } else {
1112  towner = NULL;
1113  }
1114 
1115  /* if the pet has no owner, exit with error */
1116  if (rowner == NULL) {
1117  LOG(llevError, "Pet has no owner.\n");
1118  return 0;
1119  }
1120 
1121  /* if the target is not a player, and has no owner, we shouldn't be here
1122  */
1123  if (towner == NULL && target->type != PLAYER) {
1124  LOG(llevError, "Target is not a player but has no owner. We should not be here.\n");
1125  return 0;
1126  }
1127 
1128  /* make sure that the owner is a player */
1129  if (rowner->type != PLAYER)
1130  return 0;
1131 
1132  /* abort if the petmode is not arena */
1133  if (rowner->contr->petmode != pet_arena)
1134  return 0;
1135 
1136  /* abort if the pet, it's owner, or the target is not on battleground*/
1137  if (!(op_on_battleground(pet, NULL, NULL, NULL)
1138  && op_on_battleground(owner, NULL, NULL, NULL)
1139  && op_on_battleground(target, NULL, NULL, NULL)))
1140  return 0;
1141 
1142  /* if the target is a monster, make sure it's owner is not the same */
1143  if (target->type != PLAYER && rowner == towner)
1144  return 0;
1145 
1146  /* check if the target is a player which affects how it will handle
1147  parties */
1148  if (target->type != PLAYER) {
1149  /* if the target is owned by a player make sure than make sure
1150  it's not in the same party */
1151  if (towner->type == PLAYER && rowner->contr->party != NULL) {
1152  if (rowner->contr->party == towner->contr->party)
1153  return 0;
1154  }
1155  } else {
1156  /* if the target is a player make sure than make sure it's not
1157  in the same party */
1158  if (rowner->contr->party != NULL) {
1159  if (rowner->contr->party == target->contr->party)
1160  return 0;
1161  }
1162  }
1163 
1164  return 1;
1165 }
Error, serious thing.
Definition: logger.h:11
int on_same_map(const object *op1, const object *op2)
Checks whether 2 objects are on the same map or not.
Definition: map.cpp:2628
static object * fix_summon_pet(archetype *at, object *op, int dir)
This makes multisquare/single square monsters proper for map insertion.
Definition: pets.cpp:447
#define MSG_TYPE_MISC
Messages that don&#39;t go elsewhere.
Definition: newclient.h:430
#define FLAG_NO_DROP
Object can&#39;t be dropped.
Definition: define.h:276
static void mark_inventory_as_no_drop(object *ob)
Mark all inventory items as FLAG_NO_DROP.
Definition: pets.cpp:34
uint16_t attack_movement
What kind of attack movement.
Definition: object.h:401
const char * determine_god(object *op)
Determines if op worships a god.
Definition: gods.cpp:55
object * ranges[range_size]
Object for each range.
Definition: player.h:118
#define MOVE_WALK
Object walks.
Definition: define.h:398
#define UP_OBJ_FACE
Only thing that changed was the face.
Definition: object.h:533
This is used by get_rangevector to determine where the other creature is.
Definition: map.h:375
#define AT_GHOSTHIT
Attacker dissolves (512)
Definition: attack.h:87
struct archetype * arch
Pointer to archetype.
Definition: object.h:424
const object * find_god(const char *name)
Returns a god&#39;s object from its name.
Definition: holy.cpp:317
#define FLAG_SLEEP
NPC is sleeping.
Definition: define.h:295
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
object * object_get_owner(object *op)
Returns the object which this object marks as being the owner.
Definition: object.cpp:789
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
int8_t direction
Means the object is moving that way.
Definition: object.h:344
#define FABS(x)
Decstations have trouble with fabs()...
Definition: define.h:22
int rndm(int min, int max)
Returns a number between min and max.
Definition: utils.cpp:162
#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:433
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.cpp:2867
#define FLAG_STAND_STILL
NPC will not (ever) move.
Definition: define.h:296
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
int attack_ob(object *op, object *hitter)
Simple wrapper for attack_ob_simple(), will use hitter&#39;s values.
Definition: attack.cpp:937
#define FLAG_FRIENDLY
Will help players.
Definition: define.h:233
int get_random_dir(void)
Returns a random direction (1..8).
Definition: utils.cpp:400
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:1818
#define MSG_TYPE_SPELL
Spell related info.
Definition: newclient.h:428
int16_t maxgrace
Maximum grace.
Definition: living.h:45
int level
Definition: readable.cpp:1561
#define MSG_TYPE_SPELL_FAILURE
Spell failure messages.
Definition: newclient.h:669
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.cpp:3544
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.cpp:1099
partylist * party
Party this player is part of.
Definition: player.h:205
object * more
Pointer to the rest of a large body of objects.
Definition: object.h:303
sstring slaying
Which race to do double damage to.
Definition: object.h:327
sstring add_string(const char *str)
Share a string.
Definition: shstr.cpp:137
object * monster_check_enemy(object *npc, rv_vector *rv)
Checks npc->enemy and returns that enemy if still valid, NULL otherwise.
Definition: monster.cpp:80
#define DIRX(xyz)
Definition: define.h:463
void remove_friendly_object(object *op)
Removes the specified object from the linked list of friendly objects.
Definition: friend.cpp:52
#define FLAG_CONFUSED
Will also be unable to cast spells.
Definition: define.h:299
int16_t y
Position in the map for this object.
Definition: object.h:335
int SP_level_dam_adjust(const object *caster, const object *spob)
Returns adjusted damage based on the caster.
Definition: spell_util.cpp:287
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.cpp:54
#define object_was_destroyed(op, old_tag)
Checks if an object still exists.
Definition: object.h:70
object * attacked_by
This object start to attack us! only player & monster.
Definition: object.h:392
int16_t duration
Number of moves (see &#39;speed&#39;) spell lasts.
Definition: object.h:415
#define MAX(x, y)
Definition: compat.h:24
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.cpp:825
int16_t x
Definition: object.h:335
Attack other players in arena.
Definition: player.h:61
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:502
#define safe_strncpy
Definition: compat.h:27
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
void pets_terminate_all(object *owner)
Removes all pets someone owns.
Definition: pets.cpp:242
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.cpp:308
#define MIN(x, y)
Definition: compat.h:21
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:219
#define DIRY(xyz)
Definition: define.h:464
object * owner
Pointer to the object which controls this one.
Definition: object.h:387
rangetype shoottype
Which range-attack is being used by player.
Definition: player.h:114
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.cpp:294
object * races_get_random_monster(const char *race, int level)
Get a random monster of specified race and level at most the specified one.
Definition: races.cpp:22
#define MAP_IN_MEMORY
Map is fully loaded.
Definition: map.h:129
int16_t level
Level of creature or object.
Definition: object.h:361
int16_t sp
Spell points.
Definition: living.h:42
#define FLAG_ALIVE
Object can fight (or be fought)
Definition: define.h:217
int16_t resist[NROFATTACKS]
Resistance adjustments for attacks.
Definition: object.h:351
void create_treasure(treasurelist *t, object *op, int flag, int difficulty, int tries)
This calls the appropriate treasure creation function.
Definition: treasure.cpp:287
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:483
sstring name
More definite name, like "generate_kobold".
Definition: object.h:484
float speed
Frequency of object &#39;moves&#39; relative to server tick rate.
Definition: object.h:337
int SP_level_wc_adjust(const object *caster, const object *spob)
Returns adjusted wc based on the caster and the spell.
Definition: spell_util.cpp:362
object * arch_to_object(archetype *at)
Creates and returns a new object which is a copy of the given archetype.
Definition: arch.cpp:227
#define SET_FLAG(xyz, p)
Definition: define.h:384
#define FLAG_UNAGGRESSIVE
Monster doesn&#39;t attack players.
Definition: define.h:259
#define QUERY_FLAG(xyz, p)
Definition: define.h:386
void monster_check_apply_all(object *monster)
Calls monster_check_apply() for all inventory objects.
Definition: monster.cpp:2001
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.cpp:1545
short freearr_x[SIZEOFFREE]
X offset when searching around a spot.
Definition: object.cpp:299
tag_t attacked_by_count
The tag of attacker, so we can be sure.
Definition: object.h:393
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:700
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
Control golem.
Definition: player.h:34
sstring msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:330
uint32_t golem_count
To track the golem.
Definition: player.h:121
object * head
Points to the main object of a large body.
Definition: object.h:304
sstring race
Human, goblin, dragon, etc.
Definition: object.h:326
This is a game-map.
Definition: map.h:320
Definition: object.h:150
objectlink * get_friends_of(const object *owner)
Get a list of friendly objects for the specified owner.
Definition: friend.cpp:117
#define FLAG_CHANGING
Changes to other_arch when anim is done.
Definition: define.h:250
void get_search_arr(int *search_arr)
New function to make monster searching more efficient, and effective! This basically returns a random...
Definition: object.cpp:3627
void pets_move_golem(object *op)
Handles a golem&#39;s movement.
Definition: pets.cpp:532
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.cpp:489
void pets_terminate(object *pet)
Removes a pet, taking care of clearning the owner&#39;s fields if needed.
Definition: pets.cpp:224
int monster_can_detect_enemy(object *op, object *enemy, rv_vector *rv)
Determine if we can &#39;detect&#39; the enemy.
Definition: monster.cpp:2690
#define SIZEOFFREE
Definition: define.h:155
#define P_OUT_OF_MAP
This space is outside the map.
Definition: map.h:254
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Gets the blocking state of a square.
Definition: map.h:195
int move_ob(object *op, int dir, object *originator)
Op is trying to move in direction dir.
Definition: move.cpp:58
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.cpp:4267
#define FREE_AND_CLEAR_STR(xyz)
Release the shared string, and set it to NULL.
Definition: global.h:200
int random_roll(int min, int max, const object *op, int goodbad)
Roll a random number between min and max.
Definition: utils.cpp:42
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:14
int16_t dam
How much damage this object does when hitting.
Definition: living.h:46
#define AT_PHYSICAL
Basic attack (1)
Definition: attack.h:78
#define HEAD(op)
Returns the head part of an object.
Definition: object.h:609
int freedir[SIZEOFFREE]
Direction we&#39;re pointing on this spot.
Definition: object.cpp:317
living stats
Str, Con, Dex, etc.
Definition: object.h:378
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
Many many details.
Definition: logger.h:14
int16_t invisible
How much longer the object will be invis.
Definition: object.h:370
void add_friendly_object(object *op)
Add a new friendly object to the list of friendly objects.
Definition: friend.cpp:32
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.cpp:2351
float speed_left
How much speed is left to spend this round.
Definition: object.h:338
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
uint32_t in_memory
Combination of IN_MEMORY_xxx flags.
Definition: map.h:340
#define AT_DRAIN
Victim loses 2% exp, attacker gains half of that (128)
Definition: attack.h:85
short freearr_y[SIZEOFFREE]
Y offset when searching around a spot.
Definition: object.cpp:305
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:753
See Player.
Definition: object.h:112
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
struct treasurelist * randomitems
Items to be generated.
Definition: object.h:395
object * monster_find_nearest_enemy(object *npc, object *owner)
Returns the nearest enemy (monster or generator) which is visible to npc.
Definition: monster.cpp:183
#define PREFER_HIGH
Definition: define.h:584
#define FLAG_GENERATOR
Will generate type ob->stats.food.
Definition: define.h:235
void pets_follow_owner(object *ob, object *owner)
A pet is trying to follow its owner.
Definition: pets.cpp:297
static event_registration m
Definition: citylife.cpp:424
#define RANDOM()
Definition: define.h:667
archetype * determine_holy_arch(const object *god, const char *type)
Determines the archetype for holy servant and god avatar.
Definition: gods.cpp:676
treasure * next
Next treasure-item in a linked list.
Definition: treasure.h:69
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
#define MSG_TYPE_SPELL_PET
Pet related messages.
Definition: newclient.h:668
MoveType move_type
Type of movement this object uses.
Definition: object.h:436
sstring name
The name of the object, obviously...
Definition: object.h:319
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
Stay close to the owner.
Definition: player.h:60
Only for debugging purposes.
Definition: logger.h:13
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
sstring name
Usually monster-name/combination.
Definition: treasure.h:86
void pets_move(object *ob)
Handles a pet&#39;s movement.
Definition: pets.cpp:330
void object_set_enemy(object *op, object *enemy)
Sets the enemy of an object.
Definition: object.cpp:900
void pets_attempt_follow(object *for_owner, int force)
Check pets so they try to follow their master around the world.
Definition: pets.cpp:262
#define CLEAR_FLAG(xyz, p)
Definition: define.h:385
treasure * items
Items in this list, linked.
Definition: treasure.h:92
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
int direction
General direction to the targer.
Definition: map.h:379
#define FLAG_SPLITTING
Object splits into stats.food other objs.
Definition: define.h:253
uint16_t nrof
Random 1 to nrof items are generated.
Definition: treasure.h:79
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.cpp:2522
treasure is one element in a linked list, which together consist of a complete treasure-list.
Definition: treasure.h:63
#define MIN_ACTIVE_SPEED
Cut off point of when an object is put on the active list or not.
Definition: define.h:662
int64_t exp
Experience.
Definition: living.h:47
uint32_t attacktype
Bitmask of attacks this object does.
Definition: object.h:352
#define FLAG_MONSTER
Will attack players.
Definition: define.h:232
int pets_summon_object(object *op, object *caster, object *spell_ob, int dir, const char *stringarg)
General purpose summoning function.
Definition: pets.cpp:885
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:270
#define SIZEOFFREE1
Definition: define.h:153
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.cpp:832
#define MSG_SUBTYPE_NONE
Definition: newclient.h:439
archetype * more
Next part of a linked object.
Definition: object.h:486
int absdir(int d)
Computes an absolute direction.
Definition: object.cpp:3699
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:746
StringBuffer * buf
Definition: readable.cpp:1563
static object * get_real_owner(object *ob)
Recursively look through the owner property of objects until the real owner is found.
Definition: pets.cpp:1072
struct archetype * item
Which item this link can be.
Definition: treasure.h:64
void pets_control_golem(object *op, int dir)
Makes the golem go in specified direction.
Definition: pets.cpp:643
int16_t maxhp
Max hit points.
Definition: living.h:41
#define P_IS_ALIVE
Something alive is on this space.
Definition: map.h:240
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:2085
int8_t wc
Weapon Class, lower WC increases probability of hitting.
Definition: living.h:37
int pets_summon_golem(object *op, object *caster, int dir, object *spob)
Summons a monster.
Definition: pets.cpp:664
void object_update(object *op, int action)
object_update() updates the array which represents the map.
Definition: object.cpp:1419
tag_t count
Unique object number for this object.
Definition: object.h:307
petmode_t petmode
Which petmode?
Definition: player.h:117
Try to find enemies.
Definition: player.h:59
int die_roll(int num, int size, const object *op, int goodbad)
Roll a number of dice (2d3, 4d6).
Definition: utils.cpp:122
object clone
An object from which to do object_copy()
Definition: object.h:487
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:693
int16_t hp
Hit Points.
Definition: living.h:40
Generated items have the FLAG_STARTEQUIP.
Definition: treasure.h:33
object * enemy
Monster/player to follow even if not closest.
Definition: object.h:391