Crossfire Server, Branches 1.12  R18729
pets.c
Go to the documentation of this file.
1 /*
2  * static char *rcsid_pets_c =
3  * "$Id: pets.c 11578 2009-02-23 22:02:27Z lalo $";
4  */
5 
6 /*
7  CrossFire, A Multiplayer game for X-windows
8 
9  Copyright (C) 2006 Mark Wedel & Crossfire Development Team
10  Copyright (C) 1992 Frank Tore Johansen
11 
12  This program is free software; you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation; either version 2 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program; if not, write to the Free Software
24  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 
26  The authors can be reached via e-mail at crossfire-devel@real-time.com
27 */
28 
34 #include <global.h>
35 #ifndef __CEXTRACT__
36 #include <sproto.h>
37 #endif
38 
45 static void mark_inventory_as_no_drop(object *ob) {
46  object *tmp;
47 
48  for (tmp = ob->inv; tmp != NULL; tmp = tmp->below) {
49  SET_FLAG(tmp, FLAG_NO_DROP);
50  }
51 }
52 
67 object *get_pet_enemy(object *pet, rv_vector *rv) {
68  object *owner, *tmp, *attacker, *tmp3;
69  int i;
70  sint16 x, y;
71  mapstruct *nm;
72  int search_arr[SIZEOFFREE];
73  int mflags;
74 
75  attacker = pet->attacked_by; /*pointer to attacking enemy*/
76  pet->attacked_by = NULL; /*clear this, since we are dealing with it*/
77 
78  if ((owner = get_owner(pet)) != NULL) {
79  /* If the owner has turned on the pet, make the pet
80  * unfriendly.
81  */
82  if ((check_enemy(owner, rv)) == pet) {
85  pet->attack_movement &= ~PETMOVE;
86  return owner;
87  }
88  } else {
89  /* else the owner is no longer around, so the
90  * pet no longer needs to be friendly.
91  */
94  pet->attack_movement &= ~PETMOVE;
95  return NULL;
96  }
97  /* If they are not on the same map, the pet won't be agressive */
98  if (!on_same_map(pet, owner))
99  return NULL;
100 
101  /* See if the pet has an existing enemy. If so, don't start a new one*/
102  if ((tmp = check_enemy(pet, rv)) != NULL) {
103  if (tmp == owner && !QUERY_FLAG(pet, FLAG_CONFUSED)
104  && QUERY_FLAG(pet, FLAG_FRIENDLY))
105  /* without this check, you can actually get pets with
106  * enemy set to owner!
107  */
108  pet->enemy = NULL;
109  else
110  return tmp;
111  }
112  get_search_arr(search_arr);
113 
114  if (owner->type == PLAYER && owner->contr->petmode > pet_normal) {
115  if (owner->contr->petmode == pet_sad) {
116  tmp = find_nearest_living_creature(pet);
117  if (tmp != NULL) {
118  get_rangevector(pet, tmp, rv, 0);
119  if (check_enemy(pet, rv) != NULL)
120  return tmp;
121  else
122  pet->enemy = NULL;
123  }
124  /* if we got here we have no enemy */
125  /* we return NULL to avoid heading back to the owner */
126  pet->enemy = NULL;
127  return NULL;
128  }
129  }
130 
131  /* Since the pet has no existing enemy, look for anything nasty
132  * around the owner that it should go and attack.
133  */
134  tmp3 = NULL;
135  for (i = 0; i < SIZEOFFREE; i++) {
136  x = owner->x+freearr_x[search_arr[i]];
137  y = owner->y+freearr_y[search_arr[i]];
138  nm = owner->map;
139  /* Only look on the space if there is something alive there. */
140  mflags = get_map_flags(nm, &nm, x, y, &x, &y);
141  if (!(mflags&P_OUT_OF_MAP) && mflags&P_IS_ALIVE) {
142  for (tmp = GET_MAP_OB(nm, x, y); tmp != NULL; tmp = tmp->above) {
143  object *tmp2 = tmp->head == NULL ? tmp : tmp->head;
144 
145  if (QUERY_FLAG(tmp2, FLAG_ALIVE)
146  && ((!QUERY_FLAG(tmp2, FLAG_FRIENDLY) && tmp2->type != PLAYER) || should_arena_attack(pet, owner, tmp2))
147  && !QUERY_FLAG(tmp2, FLAG_UNAGGRESSIVE)
148  && tmp2 != pet
149  && tmp2 != owner
150  && can_detect_enemy(pet, tmp2, rv)) {
151  if (!can_see_enemy(pet, tmp2)) {
152  if (tmp3 != NULL)
153  tmp3 = tmp2;
154  } else {
155  pet->enemy = tmp2;
156  if (check_enemy(pet, rv) != NULL)
157  return tmp2;
158  else
159  pet->enemy = NULL;
160  }
161  }/* if this is a valid enemy */
162  }/* for objects on this space */
163  }/* if there is something living on this space */
164  } /* for loop of spaces around the owner */
165 
166  /* fine, we went through the whole loop and didn't find one we could
167  see, take what we have */
168  if (tmp3 != NULL) {
169  pet->enemy = tmp3;
170  if (check_enemy(pet, rv) != NULL)
171  return tmp3;
172  else
173  pet->enemy = NULL;
174  }
175 
176  /* No threat to owner, check to see if the pet has an attacker*/
177  if (attacker) {
178  /* need to be sure this is the right one! */
179  if (attacker->count == pet->attacked_by_count) {
180  /* also need to check to make sure it is not freindly */
181  /* or otherwise non-hostile, and is an appropriate target */
182  if (!QUERY_FLAG(attacker, FLAG_FRIENDLY) && on_same_map(pet, attacker)) {
183  pet->enemy = attacker;
184  if (check_enemy(pet, rv) != NULL)
185  return attacker;
186  else
187  pet->enemy = NULL;
188  }
189  }
190  }
191 
192  /* Don't have an attacker or legal enemy, so look for a new one!.
193  * This looks for one around where the pet is. Thus, you could lead
194  * a pet to danger, then take a few steps back. This code is basically
195  * the same as the code that looks around the owner.
196  */
197  if (owner->type == PLAYER && owner->contr->petmode != pet_defend) {
198  tmp3 = NULL;
199  for (i = 0; i < SIZEOFFREE; i++) {
200  x = pet->x+freearr_x[search_arr[i]];
201  y = pet->y+freearr_y[search_arr[i]];
202  nm = pet->map;
203  /* Only look on the space if there is something alive there. */
204  mflags = get_map_flags(nm, &nm, x, y, &x, &y);
205  if (!(mflags&P_OUT_OF_MAP) && mflags&P_IS_ALIVE) {
206  for (tmp = GET_MAP_OB(nm, x, y); tmp != NULL; tmp = tmp->above) {
207  object *tmp2 = tmp->head == NULL ? tmp : tmp->head;
208  if (QUERY_FLAG(tmp2, FLAG_ALIVE)
209  && ((!QUERY_FLAG(tmp2, FLAG_FRIENDLY) && tmp2->type != PLAYER) || should_arena_attack(pet, owner, tmp2))
210  && !QUERY_FLAG(tmp2, FLAG_UNAGGRESSIVE)
211  && tmp2 != pet
212  && tmp2 != owner
213  && can_detect_enemy(pet, tmp2, rv)) {
214  if (!can_see_enemy(pet, tmp2)) {
215  if (tmp3 != NULL)
216  tmp3 = tmp2;
217  } else {
218  pet->enemy = tmp2;
219  if (check_enemy(pet, rv) != NULL)
220  return tmp2;
221  else
222  pet->enemy = NULL;
223  }
224  } /* make sure we can get to the bugger */
225  }/* for objects on this space */
226  } /* if there is something living on this space */
227  } /* for loop of spaces around the pet */
228  } /* pet in defence mode */
229 
230  /* fine, we went through the whole loop and didn't find one we could
231  see, take what we have */
232  if (tmp3 != NULL) {
233  pet->enemy = tmp3;
234  if (check_enemy(pet, rv) != NULL)
235  return tmp3;
236  else
237  pet->enemy = NULL;
238  }
239 
240  /* Didn't find anything - return the owner's enemy or NULL */
241  return check_enemy(pet, rv);
242 }
243 
250 void terminate_all_pets(object *owner) {
251  objectlink *obl, *next;
252 
253  for (obl = first_friendly_object; obl != NULL; obl = next) {
254  object *ob = obl->ob;
255  next = obl->next;
256  if (get_owner(ob) == owner) {
257  if (!QUERY_FLAG(ob, FLAG_REMOVED))
258  remove_ob(ob);
260  free_object(ob);
261  }
262  }
263 }
264 
273 void remove_all_pets(void) {
274  objectlink *obl, *next;
275  object *owner;
276 
277  for (obl = first_friendly_object; obl != NULL; obl = next) {
278  next = obl->next;
279  if (obl->ob->type != PLAYER
280  && QUERY_FLAG(obl->ob, FLAG_FRIENDLY)
281  && (owner = get_owner(obl->ob)) != NULL
282  && !on_same_map(owner, obl->ob)) {
283  /* follow owner checks map status for us. Note that pet can
284  * die in follow_owner, so check for obl->ob existence
285  */
286  follow_owner(obl->ob, owner);
287  if (obl->ob && QUERY_FLAG(obl->ob, FLAG_REMOVED) && FABS(obl->ob->speed) > MIN_ACTIVE_SPEED) {
288  object *ob = obl->ob;
289 
290  LOG(llevMonster, "(pet failed to follow)\n");
292  free_object(ob);
293  }
294  }
295  }
296 }
297 
306 void follow_owner(object *ob, object *owner) {
307  object *tmp;
308  int dir;
309 
310  if (!QUERY_FLAG(ob, FLAG_REMOVED))
311  remove_ob(ob);
312 
313  if (owner->map == NULL) {
314  LOG(llevError, "Can't follow owner: no map.\n");
315  return;
316  }
317  if (owner->map->in_memory != MAP_IN_MEMORY) {
318  LOG(llevError, "Owner of the pet not on a map in memory!?\n");
319  return;
320  }
321  dir = find_free_spot(ob, owner->map, owner->x, owner->y, 1, SIZEOFFREE);
322 
323  if (dir == -1) {
324  LOG(llevMonster, "No space for pet to follow, freeing %s.\n", ob->name);
325  return; /* Will be freed since it's removed */
326  }
327  for (tmp = ob; tmp != NULL; tmp = tmp->more) {
328  tmp->x = owner->x+freearr_x[dir]+(tmp->arch == NULL ? 0 : tmp->arch->clone.x);
329  tmp->y = owner->y+freearr_y[dir]+(tmp->arch == NULL ? 0 : tmp->arch->clone.y);
330  tmp->map = owner->map;
331  if (OUT_OF_REAL_MAP(tmp->map, tmp->x, tmp->y)) {
332  tmp->map = get_map_from_coord(tmp->map, &tmp->x, &tmp->y);
333  }
334  }
335  insert_ob_in_map(ob, ob->map, NULL, 0);
336  if (owner->type == PLAYER) /* Uh, I hope this is always true... */
338  "Your pet magically appears next to you", NULL);
339  return;
340 }
341 
348 void pet_move(object *ob) {
349  int dir, i;
350  tag_t tag;
351  sint16 dx, dy;
352  object *ob2, *owner;
353  mapstruct *m;
354 
355  /* Check to see if player pulled out */
356  if ((owner = get_owner(ob)) == NULL) {
357  remove_ob(ob); /* Will be freed when returning */
359  free_object(ob);
360  LOG(llevMonster, "Pet: no owner, leaving.\n");
361  return;
362  }
363 
364  /* move monster into the owners map if not in the same map */
365  if (!on_same_map(ob, owner)) {
366  follow_owner(ob, owner);
367  return;
368  }
369  /* Calculate Direction */
370  if (owner->type == PLAYER && owner->contr->petmode == pet_sad) {
371  /* in S&D mode, if we have no enemy, run randomly about. */
372  for (i = 0; i < 15; i++) {
373  dir = rndm(1, 8);
374  dx = ob->x+freearr_x[dir];
375  dy = ob->y+freearr_y[dir];
376  m = ob->map;
377  if (get_map_flags(ob->map, &m, dx, dy, &dx, &dy)&P_OUT_OF_MAP)
378  continue;
379  else if (OB_TYPE_MOVE_BLOCK(ob, GET_MAP_MOVE_BLOCK(m, dx, dy)))
380  continue;
381  else
382  break;
383  }
384  } else {
385  dir = find_dir_2(ob->x-ob->owner->x, ob->y-ob->owner->y);
386  }
387  ob->direction = dir;
388 
389  tag = ob->count;
390  /* move_ob returns 0 if the object couldn't move. If that is the
391  * case, lets do some other work.
392  */
393  if (!(move_ob(ob, dir, ob))) {
394  object *part;
395 
396  /* the failed move_ob above may destroy the pet, so check here */
397  if (was_destroyed(ob, tag))
398  return;
399 
400  for (part = ob; part != NULL; part = part->more) {
401  dx = part->x+freearr_x[dir];
402  dy = part->y+freearr_y[dir];
403  m = get_map_from_coord(part->map, &dx, &dy);
404  if (!m)
405  continue;
406 
407  for (ob2 = GET_MAP_OB(m, dx, dy); ob2 != NULL; ob2 = ob2->above) {
408  object *new_ob;
409 
410  new_ob = ob2->head ? ob2->head : ob2;
411  if (new_ob == ob)
412  break;
413  if (new_ob == ob->owner)
414  return;
415  if (get_owner(new_ob) == ob->owner)
416  break;
417 
418  /* Hmm. Did we try to move into an enemy monster? If so,
419  * make it our enemy.
420  */
421  if (QUERY_FLAG(new_ob, FLAG_ALIVE)
423  && !QUERY_FLAG(new_ob, FLAG_UNAGGRESSIVE)
424  && !QUERY_FLAG(new_ob, FLAG_FRIENDLY)) {
425  ob->enemy = new_ob;
426  if (new_ob->enemy == NULL)
427  new_ob->enemy = ob;
428  return;
429  } else if (new_ob->type == PLAYER) {
430  draw_ext_info(NDI_UNIQUE, 0, new_ob,
432  "You stand in the way of someones pet.", NULL);
433  return;
434  }
435  }
436  }
437  /* Try a different course */
438  dir = absdir(dir+4-(RANDOM()%5)-(RANDOM()%5));
439  (void)move_ob(ob, dir, ob);
440  }
441  return;
442 }
443 
444 /****************************************************************************
445  *
446  * GOLEM SPELL CODE
447  *
448  ****************************************************************************/
449 
464 static object *fix_summon_pet(archetype *at, object *op, int dir, int is_golem) {
465  archetype *atmp;
466  object *tmp = NULL, *prev = NULL, *head = NULL;
467 
468  for (atmp = at; atmp != NULL; atmp = atmp->more) {
469  tmp = arch_to_object(atmp);
470  if (atmp == at) {
471  if (!is_golem)
472  SET_FLAG(tmp, FLAG_MONSTER);
473  set_owner(tmp, op);
474  if (op->type == PLAYER) {
475  tmp->stats.exp = 0;
476  add_friendly_object(tmp);
477  SET_FLAG(tmp, FLAG_FRIENDLY);
478  if (is_golem)
479  CLEAR_FLAG(tmp, FLAG_MONSTER);
480  } else if (QUERY_FLAG(op, FLAG_FRIENDLY)) {
481  object *owner = get_owner(op);
482 
483  if (owner != NULL) {/* For now, we transfer ownership */
484  set_owner(tmp, owner);
485  tmp->attack_movement = PETMOVE;
486  add_friendly_object(tmp);
487  SET_FLAG(tmp, FLAG_FRIENDLY);
488  }
489  }
490  if (op->type != PLAYER || !is_golem) {
491  tmp->attack_movement = PETMOVE;
492  tmp->speed_left = -1;
493  tmp->type = 0;
494  tmp->enemy = op->enemy;
495  } else
496  tmp->type = GOLEM;
497  }
498  if (head == NULL)
499  head = tmp;
500  tmp->x = op->x+freearr_x[dir]+tmp->arch->clone.x;
501  tmp->y = op->y+freearr_y[dir]+tmp->arch->clone.y;
502  tmp->map = op->map;
503  if (tmp->invisible)
504  tmp->invisible = 0;
505  if (head != tmp)
506  tmp->head = head,
507  prev->more = tmp;
508  prev = tmp;
509  }
510  head->direction = dir;
511 
512  if (head->randomitems) {
513  create_treasure(head->randomitems, head, GT_APPLY|GT_STARTEQUIP, 6, 0);
514  }
516 
517  /* need to change some monster attr to prevent problems/crashing */
518  head->last_heal = 0;
519  head->last_eat = 0;
520  head->last_grace = 0;
521  head->last_sp = 0;
522  head->other_arch = NULL;
523  head->stats.exp = 0;
524  CLEAR_FLAG(head, FLAG_CHANGING);
526  CLEAR_FLAG(head, FLAG_GENERATOR);
527  CLEAR_FLAG(head, FLAG_SPLITTING);
528  if (head->attacktype&AT_GHOSTHIT)
529  head->attacktype = (AT_PHYSICAL|AT_DRAIN);
530 
531  return head;
532 }
533 
541 void move_golem(object *op) {
542  int made_attack = 0;
543  object *tmp;
544  tag_t tag;
545 
546  if (QUERY_FLAG(op, FLAG_MONSTER))
547  return; /* Has already been moved */
548 
549  if (get_owner(op) == NULL) {
550  LOG(llevDebug, "Golem without owner destructed.\n");
551  remove_ob(op);
552  free_object(op);
553  return;
554  }
555  /* It would be nice to have a cleaner way of what message to print
556  * when the golem expires than these hard coded entries.
557  * Note it is intentional that a golems duration is based on its
558  * hp, and not duration
559  */
560  if (--op->stats.hp < 0) {
561  if (op->msg)
563  op->msg, op->msg);
564  op->owner->contr->ranges[range_golem] = NULL;
565  op->owner->contr->golem_count = 0;
567  remove_ob(op);
568  free_object(op);
569  return;
570  }
571 
572  /* Do golem attacks/movement for single & multisq golems.
573  * Assuming here that op is the 'head' object. Pass only op to
574  * move_ob (makes recursive calls to other parts)
575  * move_ob returns 0 if the creature was not able to move.
576  */
577  tag = op->count;
578  if (move_ob(op, op->direction, op))
579  return;
580  if (was_destroyed(op, tag))
581  return;
582 
583  for (tmp = op; tmp; tmp = tmp->more) {
584  sint16 x = tmp->x+freearr_x[op->direction], y = tmp->y+freearr_y[op->direction];
585  object *victim;
586  mapstruct *m;
587  int mflags;
588 
589  m = op->map;
590  mflags = get_map_flags(m, &m, x, y, &x, &y);
591 
592  if (mflags&P_OUT_OF_MAP)
593  continue;
594 
595  for (victim = GET_MAP_OB(op->map, x, y); victim; victim = victim->above)
596  if (QUERY_FLAG(victim, FLAG_ALIVE))
597  break;
598 
599  /* We used to call will_hit_self to make sure we don't
600  * hit ourselves, but that didn't work, and I don't really
601  * know if that was more efficient anyways than this.
602  * This at least works. Note that victim->head can be NULL,
603  * but since we are not trying to dereferance that pointer,
604  * that isn't a problem.
605  */
606  if (victim && victim != op && victim->head != op) {
607  /* for golems with race fields, we don't attack
608  * aligned races
609  */
610 
611  if (victim->race && op->race && strstr(op->race, victim->race)) {
612  if (op->owner)
615  "%s avoids damaging %s.",
616  "%s avoids damaging %s.",
617  op->name, victim->name);
618  } else if (victim == op->owner) {
619  if (op->owner)
622  "%s avoids damaging you.",
623  "%s avoids damaging you.",
624  op->name);
625  } else {
626  attack_ob(victim, op);
627  made_attack = 1;
628  }
629  } /* If victim */
630  }
631  if (made_attack)
633 }
634 
648 void control_golem(object *op, int dir) {
649  op->direction = dir;
650 }
651 
669 int summon_golem(object *op, object *caster, int dir, object *spob) {
670  object *tmp;
671  const object *god = NULL;
672  archetype *at;
673  char buf[MAX_BUF];
674 
675  /* Because there can be different golem spells, player may want to
676  * 'lose' their old golem.
677  */
678  if (op->type == PLAYER
679  && op->contr->ranges[range_golem] != NULL
680  && op->contr->golem_count == op->contr->ranges[range_golem]->count) {
681  draw_ext_info(NDI_UNIQUE, 0, op,
683  "You dismiss your existing golem.", NULL);
686  op->contr->ranges[range_golem] = NULL;
687  op->contr->golem_count = -1;
688  }
689 
690  if (spob->other_arch)
691  at = spob->other_arch;
692  else if (spob->race) {
693  god = find_god(determine_god(caster));
694  if (!god) {
697  "You must worship a god to cast %s.",
698  "You must worship a god to cast %s.",
699  spob->name);
700  return 0;
701  }
702 
703  at = determine_holy_arch(god, spob->race);
704  if (!at) {
707  "%s has no %s for you to call.",
708  "%s has no %s for you to call.",
709  god->name, spob->race);
710  return 0;
711  }
712  } else {
713  LOG(llevError, "Spell %s lacks other_arch\n", spob->name);
714  return 0;
715  }
716 
717  if (!dir)
718  dir = find_free_spot(NULL, op->map, op->x, op->y, 1, SIZEOFFREE1+1);
719 
720  if ((dir == -1)
721  || ob_blocked(&at->clone, op->map, op->x+freearr_x[dir], op->y+freearr_y[dir])) {
722  draw_ext_info(NDI_UNIQUE, 0, op,
724  "There is something in the way.", NULL);
725  return 0;
726  }
727  /* basically want to get proper map/coordinates for this object */
728 
729  if (!(tmp = fix_summon_pet(at, op, dir, GOLEM))) {
730  draw_ext_info(NDI_UNIQUE, 0, op,
732  "Your spell fails.", NULL);
733  return 0;
734  }
735 
736  if (op->type == PLAYER) {
737  tmp->type = GOLEM;
738  set_owner(tmp, op);
739  set_spell_skill(op, caster, spob, tmp);
740  op->contr->ranges[range_golem] = tmp;
741  op->contr->golem_count = tmp->count;
742  /* give the player control of the golem */
743  op->contr->shoottype = range_golem;
744  } else {
745  if (QUERY_FLAG(op, FLAG_FRIENDLY)) {
746  object *owner = get_owner(op);
747 
748  if (owner != NULL) { /* For now, we transfer ownership */
749  set_owner(tmp, owner);
750  tmp->attack_movement = PETMOVE;
751  add_friendly_object(tmp);
752  SET_FLAG(tmp, FLAG_FRIENDLY);
753  }
754  }
755  SET_FLAG(tmp, FLAG_MONSTER);
756  }
757 
758  /* make the speed positive.*/
759  tmp->speed = FABS(tmp->speed);
760 
761  /* This sets the level dependencies on dam and hp for monsters */
762  /* players can't cope with too strong summonings. */
763  /* but monsters can. reserve these for players. */
764  if (op->type == PLAYER) {
765  tmp->stats.hp += spob->duration+SP_level_duration_adjust(caster, spob);
766  if (!spob->stats.dam)
767  tmp->stats.dam += SP_level_dam_adjust(caster, spob);
768  else
769  tmp->stats.dam = spob->stats.dam+SP_level_dam_adjust(caster, spob);
770  tmp->speed += .02*SP_level_range_adjust(caster, spob);
771  tmp->speed = MIN(tmp->speed, 1.0);
772  if (spob->attacktype)
773  tmp->attacktype = spob->attacktype;
774  }
775  tmp->stats.wc -= SP_level_range_adjust(caster, spob);
776 
777  /* limit the speed to 0.3 for non-players, 1 for players. */
778 
779  /* make experience increase in proportion to the strength.
780  * this is a bit simplistic - we are basically just looking at how
781  * often the sp doubles and use that as the ratio.
782  */
783  tmp->stats.exp *= 1+(MAX(spob->stats.maxgrace, spob->stats.sp)/caster_level(caster, spob));
784  tmp->speed_left = 0;
785  tmp->direction = dir;
786 
787  /* Holy spell - some additional tailoring */
788  if (god) {
789  object *tmp2;
790 
791  snprintf(buf, sizeof(buf), "%s of %s", spob->name, god->name);
792  buf[0] = toupper(buf[0]);
793  for (tmp2 = tmp; tmp2; tmp2 = tmp2->more) {
794  if (tmp2->name)
795  free_string(tmp2->name);
796  tmp2->name = add_string(buf);
797  }
798  tmp->attacktype |= god->attacktype;
799  memcpy(tmp->resist, god->resist, sizeof(tmp->resist));
800  if (tmp->race)
801  FREE_AND_CLEAR_STR(tmp->race);
802  if (god->race)
803  tmp->race = add_string(god->race);
804  if (tmp->slaying)
806  if (god->slaying)
807  tmp->slaying = add_string(god->slaying);
808  /* safety, we must allow a god's servants some reasonable attack */
809  if (!(tmp->attacktype&AT_PHYSICAL))
810  tmp->attacktype |= AT_PHYSICAL;
811  }
812 
813  insert_ob_in_map(tmp, tmp->map, op, 0);
814  return 1;
815 }
816 
817 /***************************************************************************
818  *
819  * Summon monster/pet/other object code
820  *
821  ***************************************************************************/
822 
837 static object *choose_cult_monster(object *pl, const object *god, int summon_level) {
838  char buf[MAX_BUF];
839  const char *race;
840  int racenr, mon_nr, i;
841  racelink *list;
842  objectlink *tobl;
843  object *otmp;
844 
845  /* Determine the number of races available */
846  racenr = 0;
847  strcpy(buf, god->race);
848  race = strtok(buf, ",");
849  while (race) {
850  racenr++;
851  race = strtok(NULL, ",");
852  }
853 
854  /* next, randomly select a race from the aligned_races string */
855  if (racenr > 1) {
856  racenr = rndm(0, racenr-1);
857  strcpy(buf, god->race);
858  race = strtok(buf, ",");
859  for (i = 0; i < racenr; i++)
860  race = strtok(NULL, ",");
861  } else
862  race = god->race;
863 
864 
865  /* see if a we can match a race list of monsters. This should not
866  * happen, so graceful recovery isn't really needed, but this sanity
867  * checking is good for cases where the god archetypes mismatch the
868  * race file
869  */
870  if ((list = find_racelink(race)) == NULL) {
873  "The spell fails! %s's creatures are beyond the range of your summons",
874  "The spell fails! %s's creatures are beyond the range of your summons",
875  god->name);
876  LOG(llevDebug, "choose_cult_monster() requested non-existent aligned race!\n");
877  return NULL;
878  }
879 
880  /* search for an apprplritate monster on this race list */
881  mon_nr = 0;
882  for (tobl = list->member; tobl; tobl = tobl->next) {
883  otmp = tobl->ob;
884  if (!otmp || !QUERY_FLAG(otmp, FLAG_MONSTER))
885  continue;
886  if (otmp->level <= summon_level)
887  mon_nr++;
888  }
889 
890  /* If this god has multiple race entries, we should really choose another.
891  * But then we either need to track which ones we have tried, or just
892  * make so many calls to this function, and if we get so many without
893  * a valid entry, assuming nothing is available and quit.
894  */
895  if (!mon_nr)
896  return NULL;
897 
898  mon_nr = rndm(0, mon_nr-1);
899  for (tobl = list->member; tobl; tobl = tobl->next) {
900  otmp = tobl->ob;
901  if (!otmp || !QUERY_FLAG(otmp, FLAG_MONSTER))
902  continue;
903  if (otmp->level <= summon_level && !mon_nr--)
904  return otmp;
905  }
906  /* This should not happen */
907  LOG(llevDebug, "choose_cult_monster() mon_nr was set, but did not find a monster\n");
908  return NULL;
909 }
910 
929 int summon_object(object *op, object *caster, object *spell_ob, int dir, const char *stringarg) {
930  sint16 x, y, nrof = 1, i;
931  archetype *summon_arch;
932  int ndir, mult;
933 
934  if (spell_ob->other_arch) {
935  summon_arch = spell_ob->other_arch;
936  } else if (spell_ob->randomitems) {
937  int level = caster_level(caster, spell_ob);
938  treasure *tr, *lasttr = NULL;
939 
940  /* In old code, this was a very convuluted for statement,
941  * with all the checks in the 'for' portion itself. Much
942  * more readable to break some of the conditions out.
943  */
944  for (tr = spell_ob->randomitems->items; tr; tr = tr->next) {
945  if (level < tr->magic)
946  break;
947  lasttr = tr;
948  if (stringarg && !strcmp(tr->item->name, stringarg))
949  break;
950  if (tr->next == NULL || tr->next->item == NULL)
951  break;
952  }
953  if (!lasttr) {
954  LOG(llevError, "Treasurelist %s did not generate a valid entry in summon_object\n", spell_ob->randomitems->name);
955  draw_ext_info(NDI_UNIQUE, 0, op,
957  "The spell fails to summon any monsters.", NULL);
958  return 0;
959  }
960  summon_arch = lasttr->item;
961  nrof = lasttr->nrof;
962 
963  } else if (spell_ob->race && !strcmp(spell_ob->race, "GODCULTMON")) {
964  const object *god = find_god(determine_god(op));
965  object *mon, *owner;
966  int summon_level, tries;
967 
968  if (!god && ((owner = get_owner(op)) != NULL)) {
969  god = find_god(determine_god(owner));
970  }
971  /* If we can't find a god, can't get what monster to summon */
972  if (!god)
973  return 0;
974 
975  if (!god->race) {
978  "%s has no creatures that you may summon!",
979  "%s has no creatures that you may summon!",
980  god->name);
981  return 0;
982  }
983  /* the summon level */
984  summon_level = caster_level(caster, spell_ob);
985  if (summon_level == 0)
986  summon_level = 1;
987  tries = 0;
988  do {
989  mon = choose_cult_monster(op, god, summon_level);
990  if (!mon) {
993  "%s fails to send anything.",
994  "%s fails to send anything.",
995  god->name);
996  return 0;
997  }
998  ndir = dir;
999  if (!ndir)
1000  ndir = find_free_spot(mon, op->map, op->x, op->y, 1, SIZEOFFREE);
1001  if (ndir == -1
1002  || ob_blocked(mon, op->map, op->x+freearr_x[ndir], op->y+freearr_y[ndir])) {
1003  ndir = -1;
1004  if (++tries == 5) {
1005  draw_ext_info(NDI_UNIQUE, 0, op,
1007  "There is something in the way.", NULL);
1008  return 0;
1009  }
1010  }
1011  } while (ndir == -1);
1012  if (mon->level > (summon_level/2))
1013  nrof = random_roll(1, 2, op, PREFER_HIGH);
1014  else
1015  nrof = die_roll(2, 2, op, PREFER_HIGH);
1016  summon_arch = mon->arch;
1017  } else {
1018  summon_arch = NULL;
1019  }
1020 
1021  if (spell_ob->stats.dam)
1022  nrof += spell_ob->stats.dam+SP_level_dam_adjust(caster, spell_ob);
1023 
1024  if (!summon_arch) {
1026  "There is no monsters available for summoning.", NULL);
1027  return 0;
1028  }
1029 
1030  if (dir) {
1031  /* Only fail if caster specified a blocked direction. */
1032  x = freearr_x[dir];
1033  y = freearr_y[dir];
1034  if (ob_blocked(&summon_arch->clone, op->map, op->x+x, op->y+y)) {
1036  "There is something in the way.", NULL);
1037  return 0;
1038  }
1039  }
1040 
1041  mult = (RANDOM()%2 ? -1 : 1);
1042 
1043  for (i = 1; i <= nrof; i++) {
1044  archetype *atmp;
1045  object *prev = NULL, *head = NULL, *tmp;
1046 
1047  if (dir) {
1048  ndir = absdir(dir+(i/2)*mult);
1049  mult = -mult;
1050  } else
1051  ndir = find_free_spot(&summon_arch->clone, op->map, op->x, op->y, 1, SIZEOFFREE);
1052 
1053  if (ndir > 0) {
1054  x = freearr_x[ndir];
1055  y = freearr_y[ndir];
1056  }
1057 
1058  if (ndir == -1 || ob_blocked(&summon_arch->clone, op->map, op->x+x, op->y+y))
1059  continue;
1060 
1061  for (atmp = summon_arch; atmp != NULL; atmp = atmp->more) {
1062  tmp = arch_to_object(atmp);
1063  if (atmp == summon_arch) {
1064  if (QUERY_FLAG(tmp, FLAG_MONSTER)) {
1065  set_owner(tmp, op);
1066  set_spell_skill(op, caster, spell_ob, tmp);
1067  tmp->enemy = op->enemy;
1068  tmp->type = 0;
1069  CLEAR_FLAG(tmp, FLAG_SLEEP);
1070  if (op->type == PLAYER || QUERY_FLAG(op, FLAG_FRIENDLY)) {
1071  /* If this is not set, we make it friendly */
1072  if (!QUERY_FLAG(spell_ob, FLAG_MONSTER)) {
1073  SET_FLAG(tmp, FLAG_FRIENDLY);
1074  add_friendly_object(tmp);
1075  tmp->stats.exp = 0;
1076  if (spell_ob->attack_movement)
1077  tmp->attack_movement = spell_ob->attack_movement;
1078  if (get_owner(op))
1079  set_owner(tmp, get_owner(op));
1080  }
1081  }
1082  }
1083  if (tmp->speed > MIN_ACTIVE_SPEED)
1084  tmp->speed_left = -1;
1085  }
1086  if (head == NULL)
1087  head = tmp;
1088  else {
1089  tmp->head = head;
1090  prev->more = tmp;
1091  }
1092  prev = tmp;
1093  tmp->x = op->x+x+tmp->arch->clone.x;
1094  tmp->y = op->y+y+tmp->arch->clone.y;
1095  tmp->map = get_map_from_coord(op->map, &tmp->x, &tmp->y);
1096  }
1097  head->direction = freedir[ndir];
1098  head->stats.exp = 0;
1099  head = insert_ob_in_map(head, head->map, op, 0);
1100  if (head && head->randomitems) {
1101  create_treasure(head->randomitems, head, GT_APPLY|GT_STARTEQUIP, 6, 0);
1102  }
1103  if (head != NULL) {
1105  }
1106  } /* for i < nrof */
1107  return 1;
1108 }
1109 
1119 static object *get_real_owner(object *ob) {
1120  object *realowner = ob;
1121 
1122  if (realowner == NULL)
1123  return NULL;
1124 
1125  while (get_owner(realowner) != NULL) {
1126  realowner = get_owner(realowner);
1127  }
1128  return realowner;
1129 }
1130 
1146 int should_arena_attack(object *pet, object *owner, object *target) {
1147  object *rowner, *towner;
1148 
1149  /* exit if the target, pet, or owner is null. */
1150  if ((target == NULL) || (pet == NULL) || (owner == NULL))
1151  return 0;
1152 
1153  /* get the owners of itself and the target, this is to deal with pets of
1154  pets */
1155  rowner = get_real_owner(owner);
1156  if (target->type != PLAYER) {
1157  towner = get_real_owner(target);
1158  } else {
1159  towner = NULL;
1160  }
1161 
1162  /* if the pet has no owner, exit with error */
1163  if (rowner == NULL) {
1164  LOG(llevError, "Pet has no owner.\n");
1165  return 0;
1166  }
1167 
1168  /* if the target is not a player, and has no owner, we shouldn't be here
1169  */
1170  if (towner == NULL && target->type != PLAYER) {
1171  LOG(llevError, "Target is not a player but has no owner. We should not be here.\n");
1172  return 0;
1173  }
1174 
1175  /* make sure that the owner is a player */
1176  if (rowner->type != PLAYER)
1177  return 0;
1178 
1179  /* abort if the petmode is not arena */
1180  if (rowner->contr->petmode != pet_arena)
1181  return 0;
1182 
1183  /* abort if the pet, it's owner, or the target is not on battleground*/
1184  if (!(op_on_battleground(pet, NULL, NULL, NULL)
1185  && op_on_battleground(owner, NULL, NULL, NULL)
1186  && op_on_battleground(target, NULL, NULL, NULL)))
1187  return 0;
1188 
1189  /* if the target is a monster, make sure it's owner is not the same */
1190  if (target->type != PLAYER && rowner == towner)
1191  return 0;
1192 
1193  /* check if the target is a player which affects how it will handle
1194  parties */
1195  if (target->type != PLAYER) {
1196  /* if the target is owned by a player make sure than make sure
1197  it's not in the same party */
1198  if (towner->type == PLAYER && rowner->contr->party != NULL) {
1199  if (rowner->contr->party == towner->contr->party)
1200  return 0;
1201  }
1202  } else {
1203  /* if the target is a player make sure than make sure it's not
1204  in the same party */
1205  if (rowner->contr->party != NULL) {
1206  if (rowner->contr->party == target->contr->party)
1207  return 0;
1208  }
1209  }
1210 
1211  return 1;
1212 }
int find_dir_2(int x, int y)
Definition: object.c:3380
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, sint16 x, sint16 y, sint16 *nx, sint16 *ny)
Definition: map.c:330
#define FLAG_NO_DROP
Definition: define.h:585
Definition: player.h:146
const char * determine_god(object *op)
Definition: gods.c:118
#define UP_OBJ_FACE
Definition: object.h:356
static void mark_inventory_as_no_drop(object *ob)
Definition: pets.c:45
signed short sint16
Definition: global.h:72
Definition: map.h:399
#define AT_GHOSTHIT
Definition: attack.h:113
#define MSG_SUBTYPE_NONE
Definition: newclient.h:339
#define FLAG_SLEEP
Definition: define.h:604
Definition: object.h:298
const char * race
Definition: object.h:171
void set_owner(object *op, object *owner)
Definition: object.c:564
object * check_enemy(object *npc, rv_vector *rv)
Definition: monster.c:83
int caster_level(const object *caster, const object *spell)
Definition: spell_util.c:237
uint16 attack_movement
Definition: object.h:242
tag_t attacked_by_count
Definition: object.h:234
#define SET_FLAG(xyz, p)
Definition: define.h:510
#define FABS(x)
Definition: define.h:61
Definition: race.h:12
#define FLAG_STAND_STILL
Definition: define.h:605
EXTERN objectlink * first_friendly_object
Definition: global.h:196
int attack_ob(object *op, object *hitter)
Definition: attack.c:929
#define FLAG_FRIENDLY
Definition: define.h:542
void move_golem(object *op)
Definition: pets.c:541
object * mon
Definition: comet_perf.c:74
void get_search_arr(int *search_arr)
Definition: object.c:3283
sint16 maxgrace
Definition: living.h:86
void free_string(sstring str)
Definition: shstr.c:272
#define MSG_TYPE_SPELL_FAILURE
Definition: newclient.h:548
struct treasureliststruct * randomitems
Definition: object.h:236
object clone
Definition: object.h:326
sint16 duration
Definition: object.h:254
sint16 invisible
Definition: object.h:211
short freearr_x[SIZEOFFREE]
Definition: object.c:75
rangetype shoottype
Definition: player.h:153
void draw_ext_info(int flags, int pri, const object *pl, uint8 type, uint8 subtype, const char *message, const char *oldmessage)
Definition: standalone.c:171
const char * slaying
Definition: object.h:172
#define FLAG_CONFUSED
Definition: define.h:608
object * ranges[range_size]
Definition: player.h:157
void update_object(object *op, int action)
Definition: object.c:1112
#define MSG_TYPE_SPELL
Definition: newclient.h:333
void control_golem(object *op, int dir)
Definition: pets.c:648
int SP_level_dam_adjust(const object *caster, const object *spob)
Definition: spell_util.c:332
sint64 exp
Definition: living.h:88
#define FLAG_SPLITTING
Definition: define.h:562
uint32 in_memory
Definition: map.h:366
struct obj * above
Definition: object.h:146
#define OUT_OF_REAL_MAP(M, X, Y)
Definition: map.h:238
int freedir[SIZEOFFREE]
Definition: object.c:93
#define GOLEM
Definition: define.h:168
sint16 x
Definition: object.h:179
void remove_friendly_object(object *op)
Definition: friend.c:69
sint16 sp
Definition: living.h:83
const object * find_god(const char *name)
Definition: gods.c:92
#define PETMOVE
Definition: define.h:826
void draw_ext_info_format(int flags, int pri, const object *pl, uint8 type, uint8 subtype, const char *new_format, const char *old_format,...)
Definition: standalone.c:175
struct obj * enemy
Definition: object.h:232
struct archt * other_arch
Definition: object.h:264
int summon_object(object *op, object *caster, object *spell_ob, int dir, const char *stringarg)
Definition: pets.c:929
int absdir(int d)
Definition: object.c:3417
Definition: object.h:321
#define PLAYER
Definition: define.h:113
struct archt * item
Definition: treasure.h:93
#define FLAG_REMOVED
Definition: define.h:528
sint16 hp
Definition: living.h:81
short freearr_y[SIZEOFFREE]
Definition: object.c:81
partylist * party
Definition: player.h:237
int summon_golem(object *op, object *caster, int dir, object *spob)
Definition: pets.c:669
void create_treasure(treasurelist *t, object *op, int flag, int difficulty, int tries)
Definition: treasure.c:499
object * ob
Definition: object.h:299
int rndm(int min, int max)
Definition: utils.c:174
uint32 tag_t
Definition: object.h:40
#define MAP_IN_MEMORY
Definition: map.h:151
struct oblnk * member
Definition: race.h:15
void remove_ob(object *op)
Definition: object.c:1515
#define FLAG_ALIVE
Definition: define.h:526
uint32 golem_count
Definition: player.h:160
float speed_left
Definition: object.h:182
racelink * find_racelink(const char *name)
Definition: init.c:1468
#define FLAG_UNAGGRESSIVE
Definition: define.h:568
struct mapdef * map
Definition: object.h:155
#define FLAG_CHANGING
Definition: define.h:559
void get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags)
Definition: map.c:2504
int SP_level_duration_adjust(const object *caster, const object *spob)
Definition: spell_util.c:357
sint16 dam
Definition: living.h:87
int die_roll(int num, int size, const object *op, int goodbad)
Definition: utils.c:134
void add_friendly_object(object *op)
Definition: friend.c:43
const char * name
Definition: object.h:167
object * get_owner(object *op)
Definition: object.c:524
struct obj * below
Definition: object.h:145
struct archt * more
Definition: object.h:325
int can_detect_enemy(object *op, object *enemy, rv_vector *rv)
Definition: monster.c:2020
void terminate_all_pets(object *owner)
Definition: pets.c:250
#define OB_TYPE_MOVE_BLOCK(ob1, type)
Definition: define.h:740
#define SIZEOFFREE
Definition: define.h:441
#define P_OUT_OF_MAP
Definition: map.h:272
mapstruct * get_map_from_coord(mapstruct *m, sint16 *x, sint16 *y)
Definition: map.c:2366
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Definition: map.h:213
int move_ob(object *op, int dir, object *originator)
Definition: move.c:72
sint16 y
Definition: object.h:179
struct pl * contr
Definition: object.h:134
int op_on_battleground(object *op, int *x, int *y, archetype **trophy)
Definition: player.c:4002
#define FREE_AND_CLEAR_STR(xyz)
Definition: global.h:283
#define MAX(x, y)
Definition: define.h:70
#define AT_PHYSICAL
Definition: attack.h:104
float speed
Definition: object.h:181
int on_same_map(const object *op1, const object *op2)
Definition: map.c:2609
#define QUERY_FLAG(xyz, p)
Definition: define.h:514
#define CLEAR_FLAG(xyz, p)
Definition: define.h:512
#define MSG_TYPE_MISC
Definition: newclient.h:335
#define MAX_BUF
Definition: define.h:81
object * insert_ob_in_map(object *op, mapstruct *m, object *originator, int flag)
Definition: object.c:1992
struct treasurestruct * items
Definition: treasure.h:119
void pet_move(object *ob)
Definition: pets.c:348
sint8 wc
Definition: living.h:79
#define AT_DRAIN
Definition: attack.h:111
#define MIN(x, y)
Definition: define.h:67
sint16 resist[NROFATTACKS]
Definition: object.h:192
int snprintf(char *dest, int max, const char *format,...)
Definition: porting.c:498
const char * name
Definition: treasure.h:112
#define PREFER_HIGH
Definition: define.h:908
uint32 attacktype
Definition: object.h:193
#define FLAG_GENERATOR
Definition: define.h:544
sint8 direction
Definition: object.h:185
struct obj * owner
Definition: object.h:228
archetype * determine_holy_arch(const object *god, const char *type)
Definition: gods.c:782
int SP_level_range_adjust(const object *caster, const object *spob)
Definition: spell_util.c:383
tag_t count
Definition: object.h:157
living stats
Definition: object.h:219
struct archt * arch
Definition: object.h:263
void set_spell_skill(object *op, object *caster, object *spob, object *dest)
Definition: spell_util.c:105
struct oblnk * next
Definition: object.h:300
int should_arena_attack(object *pet, object *owner, object *target)
Definition: pets.c:1146
static object * get_real_owner(object *ob)
Definition: pets.c:1119
void remove_all_pets(void)
Definition: pets.c:273
const char * msg
Definition: object.h:175
sstring add_string(const char *str)
Definition: shstr.c:116
#define MIN_ACTIVE_SPEED
Definition: define.h:1063
#define GET_MAP_OB(M, X, Y)
Definition: map.h:193
object * get_pet_enemy(object *pet, rv_vector *rv)
Definition: pets.c:67
int find_free_spot(const object *ob, mapstruct *m, int x, int y, int start, int stop)
Definition: object.c:3200
static object * fix_summon_pet(archetype *at, object *op, int dir, int is_golem)
Definition: pets.c:464
int can_see_enemy(object *op, object *enemy)
Definition: monster.c:2199
#define MSG_TYPE_SPELL_PET
Definition: newclient.h:547
#define FLAG_MONSTER
Definition: define.h:541
struct obj * inv
Definition: object.h:148
petmode_t petmode
Definition: player.h:156
#define NDI_UNIQUE
Definition: newclient.h:219
#define SIZEOFFREE1
Definition: define.h:439
struct obj * head
Definition: object.h:154
Definition: player.h:83
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:63
static object * choose_cult_monster(object *pl, const object *god, int summon_level)
Definition: pets.c:837
#define was_destroyed(op, old_tag)
Definition: object.h:94
uint16 nrof
Definition: treasure.h:105
object * find_nearest_living_creature(object *npc)
Definition: monster.c:162
void free_object(object *ob)
Definition: object.c:1238
Definition: map.h:346
#define P_IS_ALIVE
Definition: map.h:258
int random_roll(int min, int max, const object *op, int goodbad)
Definition: utils.c:51
struct treasurestruct * next
Definition: treasure.h:95
sint16 level
Definition: object.h:202
struct obj * more
Definition: object.h:153
object * arch_to_object(archetype *at)
Definition: arch.c:576
void follow_owner(object *ob, object *owner)
Definition: pets.c:306
const char * name
Definition: object.h:322
uint8 type
Definition: object.h:189
struct obj * attacked_by
Definition: object.h:233
int ob_blocked(const object *ob, mapstruct *m, sint16 x, sint16 y)
Definition: map.c:525