Crossfire Server, Trunk
monster.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2013 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 
20 #include "global.h"
21 
22 #include <assert.h>
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include "skills.h"
27 #include "spells.h"
28 #include "sproto.h"
29 #include "minheap.h"
30 
31 static int monster_can_hit(object *ob1, object *ob2, rv_vector *rv);
32 static int monster_cast_spell(object *head, object *part, object *pl, int dir);
33 static int monster_use_scroll(object *head, object *part, object *pl, int dir);
34 static int monster_use_skill(object *head, object *part, object *pl, int dir);
35 static int monster_use_range(object *head, object *part, object *pl, int dir);
36 static int monster_use_bow(object *head, object *part, object *pl, int dir);
37 static void monster_check_pickup(object *monster);
38 static int monster_can_pick(object *monster, object *item);
39 static void monster_apply_below(object *monster);
40 static int monster_dist_att(int dir, object *enemy, object *part, rv_vector *rv);
41 static int monster_run_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv);
42 static int monster_hitrun_att(int dir, object *ob);
43 static int monster_wait_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv);
44 static int monster_disthit_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv);
45 static int monster_wait_att2(int dir, rv_vector *rv);
46 static void monster_circ1_move(object *ob);
47 static void monster_circ2_move(object *ob);
48 static void monster_pace_movev(object *ob);
49 static void monster_pace_moveh(object *ob);
50 static void monster_pace2_movev(object *ob);
51 static void monster_pace2_moveh(object *ob);
52 static void monster_rand_move(object *ob);
53 static int monster_talk_to_npc(object *npc, talk_info *info);
54 
56 #define MIN_MON_RADIUS 3
57 
72 object *monster_check_enemy(object *npc, rv_vector *rv) {
73  object *owner;
74 
75  /* if this is pet, let him attack the same enemy as his owner
76  * TODO: when there is no ower enemy, try to find a target,
77  * which CAN attack the owner. */
78  owner = object_get_owner(npc);
79  if ((npc->attack_movement&HI4) == PETMOVE) {
80  if (owner == NULL)
81  object_set_enemy(npc, NULL);
82  else if (npc->enemy == NULL)
83  object_set_enemy(npc, owner->enemy);
84  }
85 
86  /* periodically, a monster may change its target. Also, if the object
87  * has been destroyed, etc, clear the enemy.
88  * TODO: this should be changed, because it invokes to attack forced or
89  * attacked monsters to leave the attacker alone, before it is destroyed
90  */
91  /* i had removed the random target leave, this invokes problems with friendly
92  * objects, getting attacked and defending herself - they don't try to attack
93  * again then but perhaps get attack on and on
94  * If we include a aggravated flag in , we can handle evil vs evil and good vs good
95  * too. */
96 
97  if (npc->enemy) {
98  /* I broke these if's apart to better be able to see what
99  * the grouping checks are. Code is the same.
100  */
101  if (QUERY_FLAG(npc->enemy, FLAG_REMOVED)
102  || QUERY_FLAG(npc->enemy, FLAG_FREED)
103  || !on_same_map(npc, npc->enemy)
104  || npc == npc->enemy
106  || QUERY_FLAG(npc->enemy, FLAG_NEUTRAL))
107  object_set_enemy(npc, NULL);
108 
109  else if (QUERY_FLAG(npc, FLAG_FRIENDLY) && (
110  (QUERY_FLAG(npc->enemy, FLAG_FRIENDLY) && !pets_should_arena_attack(npc, owner, npc->enemy))
111  || (npc->enemy->type == PLAYER && !pets_should_arena_attack(npc, owner, npc->enemy))
112  || npc->enemy == owner))
113  object_set_enemy(npc, NULL);
114  else if (!QUERY_FLAG(npc, FLAG_FRIENDLY)
115  && (!QUERY_FLAG(npc->enemy, FLAG_FRIENDLY) && npc->enemy->type != PLAYER))
116  object_set_enemy(npc, NULL);
117 
118  /* I've noticed that pets could sometimes get an arrow as the
119  * target enemy - this code below makes sure the enemy is something
120  * that should be attacked. My guess is that the arrow hits
121  * the creature/owner, and so the creature then takes that
122  * as the enemy to attack.
123  */
124  else if (!QUERY_FLAG(npc->enemy, FLAG_MONSTER)
125  && !QUERY_FLAG(npc->enemy, FLAG_GENERATOR)
126  && npc->enemy->type != PLAYER
127  && npc->enemy->type != GOLEM)
128  object_set_enemy(npc, NULL);
129  }
130  return monster_can_detect_enemy(npc, npc->enemy, rv) ? npc->enemy : NULL;
131 }
132 
155 object *monster_find_nearest_living_creature(object *npc, object *exclude) {
156  int i, mflags;
157  int16_t nx, ny;
158  mapstruct *m;
159  int search_arr[SIZEOFFREE];
160 
161  get_search_arr(search_arr);
162  for (i = 0; i < SIZEOFFREE; i++) {
163  /* modified to implement smart searching using search_arr
164  * guidance array to determine direction of search order
165  */
166  nx = npc->x+freearr_x[search_arr[i]];
167  ny = npc->y+freearr_y[search_arr[i]];
168  m = npc->map;
169 
170  if (nx == npc->x && ny == npc->y) {
171  continue; // Don't try to attack ourself
172  }
173 
174  mflags = get_map_flags(m, &m, nx, ny, &nx, &ny);
175  if (mflags&P_OUT_OF_MAP)
176  continue;
177 
178  if (mflags&P_IS_ALIVE) {
179  object *creature;
180 
181  creature = NULL;
182  FOR_MAP_PREPARE(m, nx, ny, tmp)
183  if ((tmp != exclude) &&
186  || tmp->type == PLAYER)) {
187  creature = tmp;
188  break;
189  }
190  FOR_MAP_FINISH();
191  if (!creature) {
192  LOG(llevDebug, "monster_find_nearest_living_creature: map %s (%d,%d) has is_alive set but did not find a monster?\n", m->path, nx, ny);
193  } else {
194  if (can_see_monsterP(m, nx, ny, i))
195  return creature;
196  }
197  } /* is something living on this space */
198  }
199  return NULL; /* nothing found */
200 }
201 
217 static object *monster_find_enemy(object *npc, rv_vector *rv) {
218  object *attacker, *tmp = NULL;
219 
220  attacker = npc->attacked_by; /* save this for later use. This can be a attacker. */
221  npc->attacked_by = NULL; /* always clear the attacker entry */
222 
223  /* if we berserk, we don't care about others - we attack all we can find */
224  if (QUERY_FLAG(npc, FLAG_BERSERK)) {
226  if (tmp == NULL)
227  return NULL;
228  if (!get_rangevector(npc, tmp, rv, 0))
229  return NULL;
230  return tmp;
231  }
232 
233  /* Here is the main enemy selection.
234  * We want this: if there is an enemy, attack him until its not possible or
235  * one of both is dead.
236  * If we have no enemy and we are...
237  * a monster: try to find a player, a pet or a friendly monster
238  * a friendly: only target a monster which is targeting you first or targeting a player
239  * a neutral: fight a attacker (but there should be none), then do nothing
240  * a pet: attack player enemy or a monster
241  */
242 
243  /* pet move */
244  if ((npc->attack_movement&HI4) == PETMOVE) {
245  tmp = pets_get_enemy(npc, rv);
246  if (tmp == NULL)
247  return NULL;
248  if (!get_rangevector(npc, tmp, rv, 0))
249  return NULL;
250  return tmp;
251  }
252 
253  /* we check our old enemy. */
254  tmp = monster_check_enemy(npc, rv);
255  if (tmp == NULL) {
256  if (attacker) { /* if we have an attacker, check him */
257  /* we want be sure this is the right one! */
258  if (attacker->count == npc->attacked_by_count) {
259  /* TODO: thats not finished */
260  /* we don't want a fight evil vs evil or good against non evil */
262  || QUERY_FLAG(attacker, FLAG_NEUTRAL) /* neutral */
264  || (!QUERY_FLAG(npc, FLAG_FRIENDLY) && (!QUERY_FLAG(attacker, FLAG_FRIENDLY) && attacker->type != PLAYER)))
265  CLEAR_FLAG(npc, FLAG_SLEEP); /* skip it, but lets wakeup */
266  else if (on_same_map(npc, attacker)) { /* thats the only thing we must know... */
267  CLEAR_FLAG(npc, FLAG_SLEEP); /* well, NOW we really should wake up! */
268  object_set_enemy(npc, attacker);
269  if (!get_rangevector(npc, attacker, rv, 0))
270  return NULL;
271  return attacker; /* yes, we face our attacker! */
272  }
273  }
274  }
275 
276  /* we have no legal enemy or attacker, so we try to target a new one */
279  && !QUERY_FLAG(npc, FLAG_NEUTRAL)) {
281  if (npc->enemy)
282  tmp = monster_check_enemy(npc, rv);
283  }
284  }
285 
286  return tmp;
287 }
288 
304 static int monster_check_wakeup(object *op, object *enemy, rv_vector *rv) {
305  int radius = MAX(op->stats.Wis, MIN_MON_RADIUS);
306 
307  /* Trim work - if no enemy, no need to do anything below */
308  if (!enemy)
309  return 0;
310 
311  /* blinded monsters can only find nearby objects to attack */
312  if (QUERY_FLAG(op, FLAG_BLIND))
313  radius = MIN_MON_RADIUS;
314 
315  /* This covers the situation where the monster is in the dark
316  * and has an enemy. If the enemy has no carried light (or isnt
317  * glowing!) then the monster has trouble finding the enemy.
318  * Remember we already checked to see if the monster can see in
319  * the dark. */
320  else if (op->map
321  && op->map->darkness > 0
322  && enemy
323  && !enemy->invisible
324  && !monster_stand_in_light(enemy)
326  int dark = radius/(op->map->darkness);
327 
328  radius = (dark > MIN_MON_RADIUS) ? (dark+1) : MIN_MON_RADIUS;
329  } else if (!QUERY_FLAG(op, FLAG_SLEEP))
330  return 1;
331 
332  /* enemy should already be on this map, so don't really need to check
333  * for that.
334  */
335  if (rv->distance < (unsigned)(QUERY_FLAG(enemy, FLAG_STEALTH) ? radius/2+1 : radius)) {
337  return 1;
338  }
339  return 0;
340 }
341 
350 static int monster_move_randomly(object *op) {
351  int i;
352  sstring talked;
353  char value[2];
354 
355  /* timeout before moving */
357  talked = object_get_value(op, "talked_to");
358  if (talked && strlen(talked) > 0) {
359  i = atoi(talked);
360  i--;
361 
362  if (i != 0) {
363  value[1] = '\0';
364  value[0] = '0' + i;
365  object_set_value(op, "talked_to", value, 1);
366  return 1;
367  }
368 
369  /* finished timeout talked to */
370  object_set_value(op, "talked_to", "", 1);
371  }
372  }
373 
374  /* Give up to 15 chances for a monster to move randomly */
375  for (i = 0; i < 15; i++) {
376  if (move_object(op, RANDOM()%8+1))
377  return 1;
378  }
379  return 0;
380 }
381 
383 #define MAX_EXPLORE 5000
384 
388 typedef struct {
389  int16_t x;
390  int16_t y;
391  uint16_t distance;
392  uint16_t heuristic_dist;
393  // This way we only have to calculate penalties once per tile per pathing calculation.
395 } path_data;
396 
406 int path_measure_func(const void *ob) {
407  const path_data *dat = (path_data *)ob;
408  return dat->distance + dat->heuristic_dist;
409 }
410 
416 static inline uint16_t estimate_distance(int16_t ax, int16_t ay, int16_t bx, int16_t by) {
417  uint16_t dx = FABS(ax - bx), dy = FABS(ay - by);
418  uint16_t diag = MIN(dx, dy);
419  return (MAX(dx, dy) - diag) * 2 + diag * 3;
420 }
421 
438 int monster_compute_path(object *source, object *target, int default_dir) {
439  path_data *distance, *current, *explore;
440  path_data *heaparr[MAX_EXPLORE];
441  int dirs[8];
442  int dir, x, y, i;
443  MinHeap heap;
444 
445  if (target->map != source->map)
446  return default_dir;
447 
448  // These shouldn't change during the calculation, so store them once to avoid dereferencing.
449  mapstruct * cur_map = source->map; // Not constant to silence some warnings.
450  const uint16_t map_height = cur_map->height;
451  /*printf("monster_compute_path (%d, %d) => (%d, %d)\n", source->x, source->y, target->x, target->y);*/
452 
453  // Leave width like this because it is used just this once.
454  const int size = cur_map->width * map_height;
455 
456  // Determine the amount by which terrain is over or under valued by the monster.
457  /* terrain value is as follows:
458  * 0 - ignore terrain penalties
459  * 1 - undervalue terrain penalties by half
460  * 2 - correctly value terrain penalties
461  * 3 - overvalue terrain penalties by 50%
462  */
463  int terrain_value;
464  if (source->attack_movement & RUSH)
465  terrain_value = 0;
466  else if (source->stats.Int < 8) {
467  terrain_value = 0;
468  }
469  else if (source->stats.Int < 13) {
470  // If low Wis, then over-value terrain penalties.
471  // Otherwise, under-value terrain penalties.
472  if (source->stats.Wis < 13) {
473  terrain_value = 3;
474  }
475  else {
476  terrain_value = 1;
477  }
478  }
479  else {
480  terrain_value = 2;
481  }
482 
493  if (!source->more) // Skip multitile monsters, since this does not work right for them
494  {
495  dir = -1; // Set a sentinel. -1 = no escape, 0 = many ways out, [1, 8] = one way out in dir
496  for (i = 1; i <= 8; ++i)
497  {
498  x = source->x + freearr_x[i];
499  y = source->y + freearr_y[i];
500  if (OUT_OF_REAL_MAP(cur_map, x, y))
501  continue;
502  if (ob_blocked(source, cur_map, x, y))
503  continue;
504  // We have a way out. Make note of it
505  if (dir < 0)
506  dir = i;
507  // We have many ways out -- do the pathing part of the function
508  else
509  {
510  dir = 0;
511  break;
512  }
513  }
514  // If dir > 0, we have our direction to go, as it is our only choice.
515  if (dir > 0)
516  return dir;
517  // If dir < 0, then we have no way to go. Return default_dir.
518  if (dir < 0)
519  return default_dir;
520  }
521 
522  /* We are setting all the values manually anyway,
523  * so there's no reason to use calloc().
524  * malloc() is more efficient here for that reason.
525  */
526  distance = malloc(size * sizeof(*distance));
527  if (distance == NULL) {
529  }
530  /*
531  * To set to 65535 efficiently, though, I need to memset each byte to 255.
532  * each element is multiple bytes, and this will fill the non-distance values, too.
533  */
534  memset(distance, 255, sizeof(*distance) * size);
535 
536  // Set current to the starting point.
537  current = &distance[map_height * target->x + target->y];
538 
539  current->distance = 0;
540  current->x = target->x;
541  current->y = target->y;
542  current->heuristic_dist = 0;
543  current->movement_penalty = 0;
544 
545  // Initialize the minheap
546  minheap_init_static(&heap, (void **)heaparr, MAX_EXPLORE, path_measure_func);
547 
548  /* The first time through, current = 0 and max = 1.
549  * This will evaluate to true, so we might as well use a do-while loop.
550  */
551  do {
552  /* Fisher–Yates shuffle the directions, "inside-out" algorithm
553  * from http://en.wikipedia.org/wiki/Fisher-Yates_shuffle */
554  dirs[0] = 1;
555  for (i = 1; i < 8; ++i) {
556  x = RANDOM() % (i+1);
557  dirs[i] = dirs[x];
558  dirs[x] = i+1;
559  }
560 
561  for (i = 0; i < 8; ++i) {
562  uint16_t new_distance;
563 
564  /*
565  * dirs[i] is the direction we wish to check.
566  */
567  dir = absdir(default_dir+4+dirs[i]);
568  x = current->x+freearr_x[dir];
569  y = current->y+freearr_y[dir];
570 
571  if (x == source->x && y == source->y) {
572  // Randomly decide to bob/weave on some steps if not RUSH movement.
573  // When not in RUSH mode, 1/4 chance of bob/weaving
574  if (source->attack_movement != RUSH && (RANDOM() & 3) == 0) {
575  // We take the perspective of the source when determining our dodge/weave direction,
576  // incorporating the required dir+4 reversal immediately.
577  int newdir = absdir(dir+4+1-(RANDOM()&2)); // Bob/weave up to one space.
578  int newx = source->x+freearr_x[newdir],
579  newy = source->y+freearr_y[newdir];
580  const path_data *newloc = &distance[map_height * newx + newy];
581  // If we checked the tile during pathing and it is not a wall and the movement penalty of the tile
582  // is not greater than the shortest-path's movement penalty, then go to that space.
583  if (newloc->distance != 65535 && newloc->distance != 1 &&
584  newloc->movement_penalty <= current->movement_penalty)
585  dir = newdir; // Commit to the bob/weave
586  else
587  dir = absdir(dir + 4);
588  }
589  // Otherwise, just follow the path we were given.
590  else
591  dir = absdir(dir + 4);
592  free(distance);
593  return dir;
594  }
595 
596  if (OUT_OF_REAL_MAP(cur_map, x, y))
597  continue;
598 
599  // Move these up, so we can reduce calls to ob_blocked with their info.
600  assert(map_height * x + y >= 0);
601  assert(map_height * x + y < size);
602 
603  // Set a pointer to the tile we are exploring.
604  explore = &distance[map_height * x + y];
605 
606  // Penalty-less spaces are handled by the inline if in the new_distance assignment.
607  // We can have move_penalty be zero because it assumes the penalty-less cost is already accounted for.
608  int16_t move_penalty = 0;
609  // Skip the penalty search if terrain value is zero. We will ignore any move penalty anyway.
610  if (terrain_value > 0) {
611  // Only calculate movement penalty if this tile does not have it yet.
612  if (explore->movement_penalty == -1) {
613  // Sum the move_slow_penalties on the map space.
614  object *tmp = GET_MAP_OB(cur_map, x, y);
616  if ((!source->move_type && tmp->move_slow&MOVE_WALK)
617  || ((source->move_type&tmp->move_slow) && (source->move_type&~tmp->move_slow&~tmp->move_block) == 0)) {
618  move_penalty += (int16_t)tmp->move_slow_penalty;
619  }
621  // And, make sure to store this for when we bump into this tile again
622  explore->movement_penalty = move_penalty;
623  }
624  else {
625  move_penalty = explore->movement_penalty;
626  }
627  }
628 
629  /* Mod 2 is equivalent to checking only the 1's bit (1 or 0), but & 1 is faster.
630  * Also, dir & 1 == 0 is true if we have a diagonal dir.
631  */
632  const int base_move_cost = ((dir & 1) == 0 ? 3 : 2);
633 
634  new_distance =
635  current->distance
636  // If terrain value is zero, we will ignore movement_penalties.
637  // If move_penalty is 0, then there were no penalties for moving onto this space.
638  + (move_penalty != 0 && terrain_value != 0 ? base_move_cost + base_move_cost * move_penalty * terrain_value / 2 : base_move_cost);
639 
640  // If already known blocked or arrivable in less distance, we skip
641  if (explore->distance <= new_distance)
642  continue;
643  // If we have a non-default value here, we will have lready done ob_blocked on it.
644  // So, only call ob_blocked if we are staring at 65535.
645  // If we are not looking at an untested space, then we will skip this block and avoid ob_blocked
646  if (explore->distance == 65535 && ob_blocked(source, cur_map, x, y))
647  {
648  // Mark as something we can't otherwise get -- the goal is to cache what spaces are blocked.
649  // At least, this call to monster_compute_path will remember this spot is blocked.
650  // This should cut our calls to ob_blocked some.
651  explore->distance = 1;
652  // The value of 1 also allows for walls to be considered already checked, but since we do not add to the
653  // explore array, this makes them hit the condition above if they are checked again without going through walls.
654  continue;
655  }
656 
657  /*LOG(llevDebug, "check %d, %d dist = %d, nd = %d\n", x, y, distance[source->map->height*x+y], new_distance);*/
658 
659  // Only set x and y when we insert into the minheap.
660  explore->x = x;
661  explore->y = y;
662  explore->distance = new_distance;
663  explore->heuristic_dist = estimate_distance(x, y, source->x, source->y); // Add a heuristic to make this A*.
664  /* printf("explore[%d] => (%d, %d) %u\n", max, x, y, new_distance);*/
665 
666  // TODO: If the space has already been evaluated, we'd really want to do an in-place update, not an insert.
667 
668  // If the heap is full when we try to insert, then we have exhausted exploration space.
669  if (minheap_insert(&heap, explore) != 0) {
670  free(distance);
671  return default_dir;
672  }
673  }
674  current = minheap_remove(&heap);
675  } while (current != NULL);
676 
677  /*LOG(llevDebug, "no path\n");*/
678  free(distance);
679  return default_dir;
680 }
681 
688 void monster_do_living(object *op) {
689  assert(op);
690  assert(QUERY_FLAG(op, FLAG_MONSTER));
691 
692  /* generate hp, if applicable */
693  if (op->stats.Con > 0 && op->stats.hp < op->stats.maxhp) {
694  /* last heal is in funny units. Dividing by speed puts
695  * the regeneration rate on a basis of time instead of
696  * #moves the monster makes. The scaling by 8 is
697  * to capture 8th's of a hp fraction regens
698  *
699  * Cast to int32_t before comparing to maxhp since otherwise an (int16_t)
700  * overflow might produce monsters with negative hp.
701  */
702 
703  op->last_heal += (int)((float)(8*op->stats.Con)/FABS(op->speed));
704  op->stats.hp = MIN((int32_t)op->stats.hp+op->last_heal/32, op->stats.maxhp); /* causes Con/4 hp/tick */
705  op->last_heal %= 32;
706 
707  /* So if the monster has gained enough HP that they are no longer afraid */
709  && op->stats.hp >= (int16_t)((int32_t)op->run_away * op->stats.maxhp / 100))
711  /*
712  * This should already be covered by the MIN() check above.
713 
714  if (op->stats.hp > op->stats.maxhp)
715  op->stats.hp = op->stats.maxhp;
716  */
717  }
718 
719  /* generate sp, if applicable */
720  if (op->stats.Pow > 0 && op->stats.sp < op->stats.maxsp) {
721  /* last_sp is in funny units. Dividing by speed puts
722  * the regeneration rate on a basis of time instead of
723  * #moves the monster makes. The scaling by 8 is
724  * to capture 8th's of a sp fraction regens
725  *
726  * Cast to int32_t before comparing to maxhp since otherwise an (int16_t)
727  * overflow might produce monsters with negative sp.
728  */
729 
730  op->last_sp += (int)((float)(8*op->stats.Pow)/FABS(op->speed));
731  op->stats.sp = MIN(op->stats.sp+op->last_sp/128, op->stats.maxsp); /* causes Pow/16 sp/tick */
732  op->last_sp %= 128;
733  }
734 
735  /* this should probably get modified by many more values.
736  * (eg, creatures resistance to fear, level, etc. )
737  */
738  if (QUERY_FLAG(op, FLAG_SCARED) && !(RANDOM()%20)) {
739  CLEAR_FLAG(op, FLAG_SCARED); /* Time to regain some "guts"... */
740  }
741 }
742 
751 static int monster_move_no_enemy(object *op) {
752  assert(QUERY_FLAG(op, FLAG_MONSTER));
753 
755  object_remove(op);
757  return 1;
758  }
759 
760  /* Probably really a bug for a creature to have both
761  * stand still and a movement type set.
762  */
763  if (!QUERY_FLAG(op, FLAG_STAND_STILL)) {
764  if (op->attack_movement&HI4) {
765  switch (op->attack_movement&HI4) {
766  case PETMOVE:
767  pets_move(op);
768  break;
769 
770  case CIRCLE1:
772  break;
773 
774  case CIRCLE2:
776  break;
777 
778  case PACEV:
780  break;
781 
782  case PACEH:
784  break;
785 
786  case PACEV2:
788  break;
789 
790  case PACEH2:
792  break;
793 
794  case RANDO:
796  break;
797 
798  case RANDO2:
800  break;
801  }
802  return 0;
803  }
804 
807  } /* stand still */
808 
809  return 0;
810 }
811 
823 int monster_move(object *op) {
824  int dir, diff;
825  object *owner, *enemy, *part;
826  rv_vector rv;
827 
828  /* Monsters not on maps don't do anything. These monsters are things
829  * Like royal guards in city dwellers inventories.
830  */
831  if (!op->map)
832  return 0;
833 
834  if (QUERY_FLAG(op, FLAG_NO_ATTACK)) { /* we never ever attack */
835  object_set_enemy(op, NULL);
836  enemy = NULL;
837  } else {
838  enemy = monster_find_enemy(op, &rv);
839  if (enemy != NULL) {
840  /* we have an enemy, just tell him we want him dead */
841  enemy->attacked_by = op; /* our ptr */
842  enemy->attacked_by_count = op->count; /* our tag */
843  }
844  }
845 
847 
848  if (QUERY_FLAG(op, FLAG_SLEEP)
850  || (op->map->darkness > 0 && !QUERY_FLAG(op, FLAG_SEE_IN_DARK) && !QUERY_FLAG(op, FLAG_SEE_INVISIBLE))) {
851  if (!monster_check_wakeup(op, enemy, &rv))
852  return 0;
853  }
854 
855  /* check if monster pops out of hidden spot */
856  if (op->hide)
858 
859  if (op->pick_up)
861 
862  if (op->will_apply)
863  monster_apply_below(op); /* Check for items to apply below */
864 
865  /* If we don't have an enemy, do special movement or the like */
866  if (!enemy) {
867  return monster_move_no_enemy(op);
868  } /* no enemy */
869 
870  /* We have an enemy. Block immediately below is for pets */
871  if ((op->attack_movement&HI4) == PETMOVE) {
872  owner = object_get_owner(op);
873  if (owner != NULL && !on_same_map(op, owner)) {
874  pets_follow_owner(op, owner);
875  /* If the pet was unable to follow the owner, free it */
876  if (QUERY_FLAG(op, FLAG_REMOVED) && FABS(op->speed) > MIN_ACTIVE_SPEED) {
879  return 1;
880  }
881  return 0;
882  }
883  }
884 
885  /* doppleganger code to change monster facing to that of the nearest
886  * player. Hmm. The code is here, but no monster in the current
887  * arch set uses it.
888  */
889  if (op->race != NULL && strcmp(op->race, "doppleganger") == 0) {
890  op->face = enemy->face;
891  if (op->name)
892  free_string(op->name);
893  add_refcount(op->name = enemy->name);
894  }
895 
896  /* Calculate range information for closest body part - this
897  * is used for the 'skill' code, which isn't that smart when
898  * it comes to figuring it out - otherwise, giants throw boulders
899  * into themselves.
900  */
901  if (!get_rangevector(op, enemy, &rv, 0))
902  return 0;
903  if (op->direction != rv.direction) {
904  op->direction = rv.direction;
905  op->facing = op->direction;
906  if (op->animation)
907  animate_object(op, op->direction);
908  }
909 
910  // We are looking at movement -- if monster was paralyzed, they aren't anymore
911  if (QUERY_FLAG(op, FLAG_PARALYZED)) {
913  }
914 
915  /* Move the check for scared up here - if the monster was scared,
916  * we were not doing any of the logic below, so might as well save
917  * a few cpu cycles.
918  */
919  if (!QUERY_FLAG(op, FLAG_SCARED)) {
920  dir = rv.direction;
921 
922  /* Was two if statements assigning to the same variable
923  * We can get the same effect by reversing the order and making an else-if
924  */
926  dir = get_randomized_dir(dir);
927  else if (QUERY_FLAG(op, FLAG_RUN_AWAY))
928  dir = absdir(dir+4);
929 
930  if (QUERY_FLAG(op, FLAG_CAST_SPELL) && !(RANDOM()%3)) {
931  if (monster_cast_spell(op, rv.part, enemy, dir))
932  return 0;
933  }
934 
935  if (QUERY_FLAG(op, FLAG_READY_SCROLL) && !(RANDOM()%3)) {
936  if (monster_use_scroll(op, rv.part, enemy, dir))
937  return 0;
938  }
939 
940  if (QUERY_FLAG(op, FLAG_READY_RANGE) && !(RANDOM()%3)) {
941  if (monster_use_range(op, rv.part, enemy, dir))
942  return 0;
943  }
944  if (QUERY_FLAG(op, FLAG_READY_SKILL) && !(RANDOM()%3)) {
945  if (monster_use_skill(op, rv.part, enemy, rv.direction))
946  return 0;
947  }
948  if (QUERY_FLAG(op, FLAG_READY_BOW) && !(RANDOM()%2)) {
949  if (monster_use_bow(op, rv.part, enemy, dir))
950  return 0;
951  }
952  } /* If not scared */
953 
954 
955  /* code below is for when we didn't use a range attack or a skill, so
956  * either move or hit with hth attack. */
957 
958  part = rv.part;
959  dir = rv.direction;
960 
961  /* This first clause used to happen after the other two, but would trample dir.
962  * Moved to before them as another check to slightly reduce calls to monster_compute_path
963  */
965  dir = get_randomized_dir(dir);
967  dir = absdir(dir+4);
968  else if (!monster_can_hit(part, enemy, &rv)) {
969  dir = monster_compute_path(op, enemy, -1);
970  if (dir == -1) {
971  // Can't reach enemy, so remove it, attempt to move in its last direction so not stay still
972  LOG(llevMonster, "monster %s (%d, %d on %s) can't reach enemy %s (%d, %d on %s)\n",
973  op->name, op->x, op->y, op->map ? op->map->name : "(unknown map)", enemy->name, enemy->x, enemy->y, enemy->map ? enemy->map->path : "(unknown map)");
974  object_set_enemy(op, NULL);
975  dir = rv.direction;
976  }
977  }
978 
979  if ((op->attack_movement&LO4) && !QUERY_FLAG(op, FLAG_SCARED)) {
980  switch (op->attack_movement&LO4) {
981  case DISTATT:
982  dir = monster_dist_att(dir, enemy, part, &rv);
983  break;
984 
985  case RUNATT:
986  dir = monster_run_att(dir, op, enemy, part, &rv);
987  break;
988 
989  case HITRUN:
990  dir = monster_hitrun_att(dir, op);
991  break;
992 
993  case WAITATT:
994  dir = monster_wait_att(dir, op, enemy, part, &rv);
995  break;
996 
997  case RUSH: /* default - monster normally moves towards player */
998  case ALLRUN:
999  break;
1000 
1001  case DISTHIT:
1002  dir = monster_disthit_att(dir, op, enemy, part, &rv);
1003  break;
1004 
1005  case WAIT2:
1006  dir = monster_wait_att2(dir, &rv);
1007  break;
1008 
1009  default:
1010  LOG(llevDebug, "Illegal low mon-move: %d\n", op->attack_movement&LO4);
1011  }
1012  }
1013 
1014  if (!dir)
1015  return 0;
1016 
1017  if (!QUERY_FLAG(op, FLAG_STAND_STILL)) {
1018  if (move_object(op, dir)) /* Can the monster move directly toward player? */
1019  return 0;
1020 
1021  if (QUERY_FLAG(op, FLAG_SCARED)
1022  || !monster_can_hit(part, enemy, &rv)
1023  || QUERY_FLAG(op, FLAG_RUN_AWAY)) {
1024  /* Try move around corners if !close */
1025  int maxdiff = (QUERY_FLAG(op, FLAG_ONLY_ATTACK) || RANDOM()&1) ? 1 : 2;
1026  for (diff = 1; diff <= maxdiff; diff++) {
1027  /* try different detours */
1028  int m = 1-(RANDOM()&2); /* Try left or right first? */
1029  if (move_object(op, absdir(dir+diff*m))
1030  || move_object(op, absdir(dir-diff*m)))
1031  return 0;
1032  }
1033  }
1034  } /* if monster is not standing still */
1035 
1036  /*
1037  * Eneq(@csd.uu.se): Patch to make RUN_AWAY or SCARED monsters move a random
1038  * direction if they can't move away.
1039  */
1043  return 0;
1044 
1045  /*
1046  * Try giving the monster a new enemy - the player that is closest
1047  * to it. In this way, it won't just keep trying to get to a target
1048  * that is inaccessible.
1049  * This could be more clever - it should go through a list of several
1050  * enemies, as it is now, you could perhaps get situations where there
1051  * are two players flanking the monster at close distance, but which
1052  * the monster can't get to, and a third one at a far distance that
1053  * the monster could get to - as it is, the monster won't look at that
1054  * third one.
1055  */
1056  if (!QUERY_FLAG(op, FLAG_FRIENDLY) && enemy == op->enemy) {
1057  object *nearest_player = get_nearest_player(op);
1058 
1059  if (nearest_player && nearest_player != enemy && !monster_can_hit(part, enemy, &rv)) {
1060  object_set_enemy(op, NULL);
1061  enemy = nearest_player;
1062  }
1063  }
1064 
1065  if (!QUERY_FLAG(op, FLAG_SCARED) && monster_can_hit(part, enemy, &rv)) {
1066  /* The adjustement to wc that was here before looked totally bogus -
1067  * since wc can in fact get negative, that would mean by adding
1068  * the current wc, the creature gets better? Instead, just
1069  * add a fixed amount - nasty creatures that are runny away should
1070  * still be pretty nasty.
1071  */
1072  if (QUERY_FLAG(op, FLAG_RUN_AWAY)) {
1073  part->stats.wc += 10;
1074  skill_attack(enemy, part, 0, NULL, NULL);
1075  part->stats.wc -= 10;
1076  } else
1077  skill_attack(enemy, part, 0, NULL, NULL);
1078  } /* if monster is in attack range */
1079 
1080  if (QUERY_FLAG(part, FLAG_FREED)) /* Might be freed by ghost-attack or hit-back */
1081  return 1;
1082 
1083  if (QUERY_FLAG(op, FLAG_ONLY_ATTACK)) {
1084  object_remove(op);
1086  return 1;
1087  }
1088  return 0;
1089 }
1090 
1105 static int monster_can_hit(object *ob1, object *ob2, rv_vector *rv) {
1106  object *more;
1107  rv_vector rv1;
1108 
1109  if (QUERY_FLAG(ob1, FLAG_CONFUSED) && !(RANDOM()%3))
1110  return 0;
1111 
1112  if (abs(rv->distance_x) < 2 && abs(rv->distance_y) < 2)
1113  return 1;
1114 
1115  /* check all the parts of ob2 - just because we can't get to
1116  * its head doesn't mean we don't want to pound its feet
1117  */
1118  for (more = ob2->more; more != NULL; more = more->more) {
1119  if (get_rangevector(ob1, more, &rv1, 0)
1120  && abs(rv1.distance_x) < 2 && abs(rv1.distance_y) < 2)
1121  return 1;
1122  }
1123  return 0;
1124 }
1125 
1148 static int monster_should_cast_spell(object *spell_ob) {
1149  /* The caller is responsible for making sure that *spell_ob is defined. */
1150  assert(spell_ob != NULL);
1151 
1152  if (spell_ob->subtype == SP_BOLT
1153  || spell_ob->subtype == SP_BULLET
1154  || spell_ob->subtype == SP_EXPLOSION
1155  || spell_ob->subtype == SP_CONE
1156  || spell_ob->subtype == SP_BOMB
1157  || spell_ob->subtype == SP_SMITE
1158  || spell_ob->subtype == SP_MAGIC_MISSILE
1159  || spell_ob->subtype == SP_SUMMON_GOLEM
1160  || spell_ob->subtype == SP_MAGIC_WALL
1161  || spell_ob->subtype == SP_SUMMON_MONSTER
1162  || spell_ob->subtype == SP_MOVING_BALL
1163  || spell_ob->subtype == SP_SWARM
1164  || spell_ob->subtype == SP_INVISIBLE)
1165  return 1;
1166 
1167  return 0;
1168 }
1169 
1171 #define MAX_KNOWN_SPELLS 20
1172 
1188 static object *monster_choose_random_spell(object *monster) {
1189  object *altern[MAX_KNOWN_SPELLS];
1190  int i = 0;
1191 
1192  FOR_INV_PREPARE(monster, tmp)
1193  if (tmp->type == SPELLBOOK || tmp->type == SPELL) {
1194  /* Check and see if it's actually a useful spell.
1195  * If its a spellbook, the spell is actually the inventory item.
1196  * if it is a spell, then it is just the object itself.
1197  */
1198  if (monster_should_cast_spell(tmp->type == SPELLBOOK ? tmp->inv : tmp)) {
1199  altern[i++] = tmp;
1200  if (i == MAX_KNOWN_SPELLS)
1201  break;
1202  }
1203  }
1204  FOR_INV_FINISH();
1205  if (!i)
1206  return NULL;
1207  return altern[RANDOM()%i];
1208 }
1209 
1226 static int monster_cast_spell(object *head, object *part, object *pl, int dir) {
1227  object *spell_item;
1228  object *owner;
1229  rv_vector rv1;
1230 
1231  /* If you want monsters to cast spells over friends, this spell should
1232  * be removed. It probably should be in most cases, since monsters still
1233  * don't care about residual effects (ie, casting a cone which may have a
1234  * clear path to the player, the side aspects of the code will still hit
1235  * other monsters)
1236  */
1237  dir = path_to_player(part, pl, 0);
1238  if (dir == 0)
1239  return 0;
1240 
1241  if (QUERY_FLAG(head, FLAG_FRIENDLY)) {
1242  owner = object_get_owner(head);
1243  if (owner != NULL) {
1244  if (get_rangevector(head, owner, &rv1, 0x1)
1245  && dirdiff(dir, rv1.direction) < 2) {
1246  return 0; /* Might hit owner with spell */
1247  }
1248  }
1249  }
1250 
1251  if (QUERY_FLAG(head, FLAG_CONFUSED))
1252  dir = get_randomized_dir(dir);
1253 
1254  /* If the monster hasn't already chosen a spell, choose one
1255  * I'm not sure if it really make sense to pre-select spells (events
1256  * could be different by the time the monster goes again).
1257  */
1258  if (head->spellitem == NULL) {
1259  spell_item = monster_choose_random_spell(head);
1260  if (spell_item == NULL) {
1261  LOG(llevMonster, "Turned off spells in %s\n", head->name);
1262  CLEAR_FLAG(head, FLAG_CAST_SPELL); /* Will be turned on when picking up book */
1263  return 0;
1264  }
1265  if (spell_item->type == SPELLBOOK) {
1266  if (!spell_item->inv) {
1267  LOG(llevError, "spellbook %s does not contain a spell?\n", spell_item->name);
1268  return 0;
1269  }
1270  spell_item = spell_item->inv;
1271  }
1272  } else
1273  spell_item = head->spellitem;
1274 
1275  if (!spell_item)
1276  return 0;
1277 
1278  /* Best guess this is a defensive/healing spell */
1279  if (spell_item->range <= 1 || spell_item->stats.dam < 0)
1280  dir = 0;
1281 
1282  /* Monster doesn't have enough spell-points */
1283  if (head->stats.sp < SP_level_spellpoint_cost(head, spell_item, SPELL_MANA))
1284  return 0;
1285 
1286  if (head->stats.grace < SP_level_spellpoint_cost(head, spell_item, SPELL_GRACE))
1287  return 0;
1288 
1289  head->stats.sp -= SP_level_spellpoint_cost(head, spell_item, SPELL_MANA);
1290  head->stats.grace -= SP_level_spellpoint_cost(head, spell_item, SPELL_GRACE);
1291 
1292  /* set this to null, so next time monster will choose something different */
1293  head->spellitem = NULL;
1294 
1295  return cast_spell(part, part, dir, spell_item, NULL);
1296 }
1297 
1312 static int monster_use_scroll(object *head, object *part, object *pl, int dir) {
1313  object *scroll;
1314  object *owner;
1315  rv_vector rv1;
1316 
1317  /* If you want monsters to cast spells over friends, this spell should
1318  * be removed. It probably should be in most cases, since monsters still
1319  * don't care about residual effects (ie, casting a cone which may have a
1320  * clear path to the player, the side aspects of the code will still hit
1321  * other monsters)
1322  */
1323  dir = path_to_player(part, pl, 0);
1324  if (dir == 0)
1325  return 0;
1326 
1327  if (QUERY_FLAG(head, FLAG_FRIENDLY)) {
1328  owner = object_get_owner(head);
1329  if (owner != NULL) {
1330  if (get_rangevector(head, owner, &rv1, 0x1)
1331  && dirdiff(dir, rv1.direction) < 2) {
1332  return 0; /* Might hit owner with spell */
1333  }
1334  }
1335  }
1336 
1337  if (QUERY_FLAG(head, FLAG_CONFUSED))
1338  dir = get_randomized_dir(dir);
1339 
1340  scroll = NULL;
1341  FOR_INV_PREPARE(head, tmp)
1342  if (tmp->type == SCROLL && monster_should_cast_spell(tmp->inv)) {
1343  scroll = tmp;
1344  break;
1345  }
1346  FOR_INV_FINISH();
1347 
1348  /* Used up all his scrolls, so nothing do to */
1349  if (!scroll) {
1351  return 0;
1352  }
1353 
1354  /* Spell should be cast on caster (ie, heal, strength) */
1355  if (scroll->inv->range == 0)
1356  dir = 0;
1357 
1358  /* Face the direction that we want to cast. */
1359  head->direction = dir;
1360  head->facing = head->direction;
1361  if (head->animation)
1362  animate_object(head, head->direction);
1363 
1364  apply_manual(part, scroll, 0);
1365  return 1;
1366 }
1367 
1396 static int monster_use_skill(object *head, object *part, object *pl, int dir) {
1397  object *owner;
1398  int found;
1399 
1400  dir = path_to_player(part, pl, 0);
1401  if (dir == 0)
1402  return 0;
1403 
1404  if (QUERY_FLAG(head, FLAG_FRIENDLY)) {
1405  owner = object_get_owner(head);
1406  if (owner != NULL) {
1407  rv_vector rv;
1408 
1409  if (get_rangevector(head, owner, &rv, 0) && dirdiff(dir, rv.direction) < 1)
1410  return 0; /* Might hit owner with skill -thrown rocks for example ?*/
1411  }
1412  }
1413  if (QUERY_FLAG(head, FLAG_CONFUSED))
1414  dir = get_randomized_dir(dir);
1415 
1416  /* skill selection - monster will use the next unused skill.
1417  * well...the following scenario will allow the monster to
1418  * toggle between 2 skills. One day it would be nice to make
1419  * more skills available to monsters.
1420  */
1421  found = 0;
1422  FOR_INV_PREPARE(head, skill)
1423  if (skill->type == SKILL && skill != head->chosen_skill) {
1424  head->chosen_skill = skill;
1425  found = 1;
1426  break;
1427  }
1428  FOR_INV_FINISH();
1429 
1430  if (!found && !head->chosen_skill) {
1431  LOG(llevDebug, "Error: Monster %s (%d) has FLAG_READY_SKILL without skill.\n", head->name, head->count);
1433  return 0;
1434  }
1435  /* use skill */
1436  return do_skill(head, part, head->chosen_skill, dir, NULL);
1437 }
1438 
1453 static int monster_use_range(object *head, object *part, object *pl, int dir) {
1454  object *owner;
1455  int at_least_one = 0;
1456 
1457  dir = path_to_player(part, pl, 0);
1458  if (dir == 0)
1459  return 0;
1460 
1461  if (QUERY_FLAG(head, FLAG_FRIENDLY)) {
1462  owner = object_get_owner(head);
1463  if (owner != NULL) {
1464  rv_vector rv;
1465 
1466  if (get_rangevector(head, owner, &rv, 0) && dirdiff(dir, rv.direction) < 2)
1467  return 0; /* Might hit owner with spell */
1468  }
1469  }
1470  if (QUERY_FLAG(head, FLAG_CONFUSED))
1471  dir = get_randomized_dir(dir);
1472 
1473  FOR_INV_PREPARE(head, wand) {
1474  if (wand->type == WAND) {
1475  /* Found a wand, let's see if it has charges left */
1476  at_least_one = 1;
1477  if (wand->stats.food <= 0)
1478  continue;
1479 
1480  cast_spell(head, wand, dir, wand->inv, NULL);
1481  drain_wand_charge(wand);
1482 
1483  /* Success */
1484  return 1;
1485  }
1486 
1487  if (wand->type == ROD) {
1488  /* Found rod/horn, let's use it if possible */
1489  at_least_one = 1;
1490  if (wand->stats.hp < MAX(wand->inv->stats.sp, wand->inv->stats.grace))
1491  continue;
1492 
1493  /* drain charge before casting spell - can be a case where the
1494  * spell destroys the monster, and rod, so if done after, results
1495  * in crash.
1496  */
1497  drain_rod_charge(wand);
1498  cast_spell(head, wand, dir, wand->inv, NULL);
1499 
1500  /* Success */
1501  return 1;
1502  }
1503  } FOR_INV_FINISH();
1504 
1505  if (at_least_one)
1506  return 0;
1507 
1508  LOG(llevError, "Error: Monster %s (%d) HAS_READY_RANG() without wand/horn/rod.\n", head->name, head->count);
1510  return 0;
1511 }
1512 
1529 static int monster_use_bow(object *head, object *part, object *pl, int dir) {
1530  object *owner;
1531  rv_vector rv;
1532  int16_t x, y;
1533  mapstruct *map;
1534 
1535  if (!get_rangevector(part, pl, &rv, 1))
1536  return 0;
1537  if (rv.distance > 100)
1538  /* Too far */
1539  return 0;
1540  if (rv.distance_x != 0 && rv.distance_y != 0 && abs(rv.distance_x) != abs(rv.distance_y))
1541  /* Player must be on same horizontal, vertical or diagonal line. */
1542  return 0;
1543  dir = rv.direction;
1544 
1545  if (QUERY_FLAG(head, FLAG_FRIENDLY))
1546  owner = object_get_owner(head);
1547  else
1548  owner = NULL;
1549 
1550  /* The monster can possibly fire, let's see if the path is ok for an arrow. */
1551  x = part->x;
1552  y = part->y;
1553  map = part->map;
1554  while (x != pl->x || y != pl->y || map != pl->map) {
1555  x += freearr_x[dir];
1556  y += freearr_y[dir];
1557  map = get_map_from_coord(map, &x, &y);
1558  if (!map) {
1559  LOG(llevError, "monster_use_bow: no map but still path exists??\n");
1560  return 0;
1561  }
1563  return 0;
1564  if (owner && owner->x == x && owner->y == y && owner->map == map)
1565  /* Don't hit owner! */
1566  return 0;
1567  }
1568 
1569  /* Finally, path is clear, can fire. */
1570 
1571  if (QUERY_FLAG(head, FLAG_CONFUSED))
1572  dir = get_randomized_dir(dir);
1573 
1574  /* in server/player.c */
1575  return fire_bow(head, NULL, dir, 0, part->x, part->y);
1576 }
1577 
1586 static int monster_get_weapon_quality(const object *item) {
1587  int val;
1588  int i;
1589 
1590  val = item->stats.dam;
1591  val += item->magic*3;
1592  /* Monsters don't really get benefits from things like regen rates
1593  * from items. But the bonus for their stats are very important.
1594  */
1595  for (i = 0; i < NUM_STATS; i++)
1596  val += get_attr_value(&item->stats, i)*2;
1597  return val;
1598 }
1599 
1612 static int monster_check_good_weapon(object *who, object *item) {
1613  object *other_weap;
1614  int val;
1615 
1616  other_weap = object_find_by_type_applied(who, item->type);
1617  if (other_weap == NULL) /* No other weapons */
1618  return 1;
1619 
1620  /* Rather than go through and apply the new one, and see if it is
1621  * better, just do some simple checks
1622  * Put some multipliers for things that hvae several effects,
1623  * eg, magic affects both damage and wc, so it has more weight
1624  */
1625 
1627  return val > 0;
1628 }
1629 
1638 static int monster_get_armour_quality(const object *item) {
1639  int val;
1640 
1641  val = item->stats.ac;
1642  val += item->resist[ATNR_PHYSICAL]/5;
1643  val += item->magic*3;
1644  return val;
1645 }
1646 
1659 static int monster_check_good_armour(object *who, object *item) {
1660  object *other_armour;
1661  int val, i;
1662 
1663  other_armour = object_find_by_type_applied(who, item->type);
1664  if (other_armour == NULL) /* No other armour, use the new */
1665  return 1;
1666 
1668 
1669  /* for the other protections, do weigh them very much in the equation -
1670  * it is the armor protection which is most important, because there is
1671  * no good way to know what the player may attack the monster with.
1672  * So if the new item has better protection than the old, give that higher
1673  * value. If the reverse, then decrease the value of this item some.
1674  */
1675  for (i = 1; i < NROFATTACKS; i++) {
1676  if (item->resist[i] > other_armour->resist[i])
1677  val++;
1678  else if (item->resist[i] < other_armour->resist[i])
1679  val--;
1680  }
1681 
1682  /* Very few armours have stats, so not much need to worry about those. */
1683 
1684  return val > 0;
1685 }
1686 
1694 static void monster_check_apply(object *mon, object *item) {
1695  int flag = 0;
1696 
1697  if (item->type == SPELLBOOK
1698  && mon->arch != NULL
1699  && (QUERY_FLAG(&mon->arch->clone, FLAG_CAST_SPELL))) {
1701  return;
1702  }
1703 
1704  /* If for some reason, this item is already applied, no more work to do */
1706  return;
1707 
1708  /* Might be better not to do this - if the monster can fire a bow,
1709  * it is possible in his wanderings, he will find one to use. In
1710  * which case, it would be nice to have ammo for it.
1711  */
1712  if (QUERY_FLAG(mon, FLAG_USE_BOW) && item->type == ARROW) {
1713  /* Check for the right kind of bow */
1714  object *bow;
1715 
1716  bow = object_find_by_type_and_race(mon, BOW, item->race);
1717  if (bow != NULL) {
1719  LOG(llevMonster, "Found correct bow for arrows.\n");
1720  return; /* nothing more to do for arrows */
1721  }
1722  }
1723 
1724  if (item->type == TREASURE && mon->will_apply&WILL_APPLY_TREASURE)
1725  flag = 1;
1726  /* Eating food gets hp back */
1727  else if (item->type == FOOD && mon->will_apply&WILL_APPLY_FOOD)
1728  flag = 1;
1729  else if (item->type == SCROLL && QUERY_FLAG(mon, FLAG_USE_SCROLL)) {
1730  if (!item->inv)
1731  LOG(llevDebug, "Monster %d having scroll %d with empty inventory!\n", mon->count, item->count);
1732  else if (monster_should_cast_spell(item->inv))
1734  /* Don't use it right now */
1735  return;
1736  } else if (item->type == WEAPON)
1738  else if (IS_ARMOR(item) || IS_SHIELD(item))
1740  /* Should do something more, like make sure this is a better item */
1741  else if (item->type == RING)
1742  flag = 1;
1743  else if (item->type == WAND || item->type == ROD) {
1744  /* We never really 'ready' the wand/rod/horn, because that would mean the
1745  * weapon would get undone.
1746  */
1750  }
1751  return;
1752  } else if (item->type == BOW) {
1753  /* We never really 'ready' the bow, because that would mean the
1754  * weapon would get undone.
1755  */
1758  return;
1759  } else if (item->type == SKILL) {
1760  /*
1761  * skills are specials: monsters must have the 'FLAG_READY_SKILL' flag set,
1762  * else they can't use the skill...
1763  * Skills also don't need to get applied, so return now.
1764  */
1766  return;
1767  }
1768 
1769  /* if we don't match one of the above types, return now.
1770  * apply_can_apply_object() will say that we can apply things like flesh,
1771  * bolts, and whatever else, because it only checks against the
1772  * body_info locations.
1773  */
1774  if (!flag)
1775  return;
1776 
1777  /* Check to see if the monster can use this item. If not, no need
1778  * to do further processing. Note that apply_can_apply_object() already checks
1779  * for the CAN_USE flags.
1780  */
1782  return;
1783 
1784  /* should only be applying this item, not unapplying it.
1785  * also, ignore status of curse so they can take off old armour.
1786  * monsters have some advantages after all.
1787  */
1789  return;
1790 }
1791 
1811 static void monster_check_pickup(object *monster) {
1812  object *part;
1813 
1814  for (part = monster; part != NULL; part = part->more)
1815  FOR_BELOW_PREPARE(part, tmp) {
1816  /* Don't try to pick items that are in the process of being thrown.
1817  * It is fairly likely that an ally threw it past monster to hit player.
1818  * IDEA: Maybe have a dex save to catch player-thrown projectiles?
1819  *
1820  * Daniel Hawkins 2020-09-07
1821  */
1822  if (tmp->type != THROWN_OBJ && monster_can_pick(monster, tmp)) {
1823  uint32_t nrof;
1824 
1825  if (tmp->weight > 0) {
1826  int32_t weight_limit;
1827 
1828  weight_limit = get_weight_limit(monster->stats.Str);
1829  if (weight_limit >= monster->weight-monster->carrying)
1830  nrof = (weight_limit-monster->weight-monster->carrying)/tmp->weight;
1831  else
1832  nrof = 0;
1833  } else
1834  nrof = MAX(1, tmp->nrof);
1835  if (nrof >= 1) {
1836  object *tmp2;
1837 
1838  tmp2 = object_split(tmp, MIN(nrof, MAX(1, tmp->nrof)), NULL, 0);
1839  tmp2 = object_insert_in_ob(tmp2, monster);
1840  (void)monster_check_apply(monster, tmp2);
1841  }
1842  }
1843  } FOR_BELOW_FINISH();
1844 }
1845 
1855 static int monster_can_pick(object *monster, object *item) {
1856  int flag = 0;
1857  int i;
1858 
1859  if (!object_can_pick(monster, item))
1860  return 0;
1861 
1862  if (QUERY_FLAG(item, FLAG_UNPAID))
1863  return 0;
1864 
1865  if (monster->pick_up&64) /* All */
1866  flag = 1;
1867 
1868  else {
1869  if (IS_WEAPON(item))
1870  flag = (monster->pick_up&8) || QUERY_FLAG(monster, FLAG_USE_WEAPON);
1871  else if (IS_ARMOR(item))
1872  flag = (monster->pick_up&16) || QUERY_FLAG(monster, FLAG_USE_ARMOUR);
1873  else if (IS_SHIELD(item))
1874  flag = (monster->pick_up&16) || QUERY_FLAG(monster, FLAG_USE_SHIELD);
1875  else switch (item->type) {
1876  case MONEY:
1877  case GEM:
1878  flag = monster->pick_up&2;
1879  break;
1880 
1881  case FOOD:
1882  flag = monster->pick_up&4;
1883  break;
1884 
1885  case SKILL:
1886  flag = QUERY_FLAG(monster, FLAG_CAN_USE_SKILL);
1887  break;
1888 
1889  case RING:
1890  flag = QUERY_FLAG(monster, FLAG_USE_RING);
1891  break;
1892 
1893  case WAND:
1894  case ROD:
1895  flag = QUERY_FLAG(monster, FLAG_USE_RANGE);
1896  break;
1897 
1898  case SPELLBOOK:
1899  flag = (monster->arch != NULL && QUERY_FLAG(&monster->arch->clone, FLAG_CAST_SPELL));
1900  break;
1901 
1902  case SCROLL:
1903  flag = QUERY_FLAG(monster, FLAG_USE_SCROLL);
1904  break;
1905 
1906  case BOW:
1907  case ARROW:
1908  flag = QUERY_FLAG(monster, FLAG_USE_BOW);
1909  break;
1910  }
1911  if (!flag && QUERY_FLAG(item, FLAG_IS_THROWN) && object_find_by_type_subtype(monster, SKILL, SK_THROWING) != NULL)
1912  flag = (monster->pick_up&8) || QUERY_FLAG(monster, FLAG_USE_WEAPON);
1913  /* Simplistic check - if the monster has a location to equip it, he will
1914  * pick it up. Note that this doesn't handle cases where an item may
1915  * use several locations.
1916  */
1917  for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
1918  if (monster->body_info[i] && item->body_info[i]) {
1919  flag = 1;
1920  break;
1921  }
1922  }
1923  }
1924 
1925  if (((!(monster->pick_up&32)) && flag) || ((monster->pick_up&32) && (!flag)))
1926  return 1;
1927  return 0;
1928 }
1929 
1936 static void monster_apply_below(object *monster) {
1937  FOR_BELOW_PREPARE(monster, tmp) {
1938  switch (tmp->type) {
1939  case CF_HANDLE:
1940  case TRIGGER:
1941  if (monster->will_apply&WILL_APPLY_HANDLE)
1942  apply_manual(monster, tmp, 0);
1943  break;
1944 
1945  case TREASURE:
1946  if (monster->will_apply&WILL_APPLY_TREASURE)
1947  apply_manual(monster, tmp, 0);
1948  break;
1949  }
1951  break;
1952  } FOR_BELOW_FINISH();
1953 }
1954 
1959 void monster_check_apply_all(object *monster) {
1960  if (!monster->head) {
1961  fix_object(monster); // Needed to correctly fill various body fields.
1962  }
1963  FOR_INV_PREPARE(monster, inv)
1964  monster_check_apply(monster, inv);
1965  FOR_INV_FINISH();
1966 }
1967 
1972 void monster_npc_call_help(object *op) {
1973  const int help_radius = 3;
1974  for (int x = -help_radius; x <= help_radius; x++)
1975  for (int y = -help_radius; y <= help_radius; y++) {
1976  mapstruct *m = op->map;
1977  int16_t sx = op->x+x;
1978  int16_t sy = op->y+y;
1979  int mflags = get_map_flags(m, &m, sx, sy, &sx, &sy);
1980  /* If nothing alive on this space, no need to search the space. */
1981  if ((mflags&P_OUT_OF_MAP) || !(mflags&P_IS_ALIVE))
1982  continue;
1983 
1984  FOR_MAP_PREPARE(m, sx, sy, npc)
1986  object_set_enemy(npc, op->enemy);
1987  FOR_MAP_FINISH();
1988  }
1989 }
1990 
1999 static int monster_dist_att(int dir, object *enemy, object *part, rv_vector *rv) {
2000  if (monster_can_hit(part, enemy, rv))
2001  return dir;
2002  if (rv->distance < 10)
2003  return absdir(dir+4);
2004  else if (rv->distance > 18)
2005  return dir;
2006  return 0;
2007 }
2008 
2018 static int monster_run_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv) {
2019  if ((monster_can_hit(part, enemy, rv) && ob->move_status < 20) || ob->move_status < 20) {
2020  ob->move_status++;
2021  return (dir);
2022  } else if (ob->move_status > 20)
2023  ob->move_status = 0;
2024  return absdir(dir+4);
2025 }
2026 
2033 static int monster_hitrun_att(int dir, object *ob) {
2034  if (ob->move_status++ < 25)
2035  return dir;
2036  else if (ob->move_status < 50)
2037  return absdir(dir+4);
2038  ob->move_status = 0;
2039  return absdir(dir+4);
2040 }
2041 
2051 static int monster_wait_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv) {
2052  int inrange = monster_can_hit(part, enemy, rv);
2053 
2054  if (ob->move_status || inrange)
2055  ob->move_status++;
2056 
2057  if (ob->move_status == 0)
2058  return 0;
2059  else if (ob->move_status < 10)
2060  return dir;
2061  else if (ob->move_status < 15)
2062  return absdir(dir+4);
2063  ob->move_status = 0;
2064  return 0;
2065 }
2066 
2076 static int monster_disthit_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv) {
2077  /* The logic below here looked plain wrong before. Basically, what should
2078  * happen is that if the creatures hp percentage falls below run_away,
2079  * the creature should run away (dir+4)
2080  * I think its wrong for a creature to have a zero maxhp value, but
2081  * at least one map has this set, and whatever the map contains, the
2082  * server should try to be resilant enough to avoid the problem
2083  */
2084  if (ob->stats.maxhp && (ob->stats.hp*100)/ob->stats.maxhp < ob->run_away)
2085  return absdir(dir+4);
2086  return monster_dist_att(dir, enemy, part, rv);
2087 }
2088 
2095 static int monster_wait_att2(int dir, rv_vector *rv) {
2096  if (rv->distance < 9)
2097  return absdir(dir+4);
2098  return 0;
2099 }
2100 
2105 static void monster_circ1_move(object *ob) {
2106  static const int circle [12] = { 3, 3, 4, 5, 5, 6, 7, 7, 8, 1, 1, 2 };
2107 
2108  if (++ob->move_status > 11)
2109  ob->move_status = 0;
2110  if (!(move_object(ob, circle[ob->move_status])))
2111  (void)move_object(ob, RANDOM()%8+1);
2112 }
2113 
2118 static void monster_circ2_move(object *ob) {
2119  static const int circle[20] = { 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 1, 1, 1, 2, 2 };
2120 
2121  if (++ob->move_status > 19)
2122  ob->move_status = 0;
2123  if (!(move_object(ob, circle[ob->move_status])))
2124  (void)move_object(ob, RANDOM()%8+1);
2125 }
2126 
2131 static void monster_pace_movev(object *ob) {
2132  if (ob->move_status++ > 6)
2133  ob->move_status = 0;
2134  if (ob->move_status < 4)
2135  (void)move_object(ob, 5);
2136  else
2137  (void)move_object(ob, 1);
2138 }
2139 
2144 static void monster_pace_moveh(object *ob) {
2145  if (ob->move_status++ > 6)
2146  ob->move_status = 0;
2147  if (ob->move_status < 4)
2148  (void)move_object(ob, 3);
2149  else
2150  (void)move_object(ob, 7);
2151 }
2152 
2157 static void monster_pace2_movev(object *ob) {
2158  if (ob->move_status++ > 16)
2159  ob->move_status = 0;
2160  if (ob->move_status < 6)
2161  (void)move_object(ob, 5);
2162  else if (ob->move_status < 8)
2163  return;
2164  else if (ob->move_status < 13)
2165  (void)move_object(ob, 1);
2166 }
2167 
2172 static void monster_pace2_moveh(object *ob) {
2173  if (ob->move_status++ > 16)
2174  ob->move_status = 0;
2175  if (ob->move_status < 6)
2176  (void)move_object(ob, 3);
2177  else if (ob->move_status < 8)
2178  return;
2179  else if (ob->move_status < 13)
2180  (void)move_object(ob, 7);
2181 }
2182 
2187 static void monster_rand_move(object *ob) {
2188  int i;
2189 
2190  if (ob->move_status < 1
2191  || ob->move_status > 8
2192  || !(move_object(ob, ob->move_status || !(RANDOM()%9))))
2193  for (i = 0; i < 5; i++) {
2194  ob->move_status = RANDOM()%8+1;
2195  if (move_object(ob, ob->move_status))
2196  return;
2197  }
2198 }
2199 
2207 void monster_check_earthwalls(object *op, mapstruct *m, int x, int y) {
2208  FOR_MAP_PREPARE(m, x, y, tmp)
2209  if (tmp->type == EARTHWALL) {
2210  hit_player(tmp, op->stats.dam, op, AT_PHYSICAL, 1);
2211  return;
2212  }
2213  FOR_MAP_FINISH();
2214 }
2215 
2223 void monster_check_doors(object *op, mapstruct *m, int x, int y) {
2224  FOR_MAP_PREPARE(m, x, y, tmp)
2225  if (tmp->type == DOOR) {
2226  hit_player(tmp, op->stats.dam, op, AT_PHYSICAL, 1);
2227  return;
2228  }
2229  FOR_MAP_FINISH();
2230 }
2231 
2237 void monster_do_say(const mapstruct *map, const char *message) {
2239  message);
2240 }
2241 
2248 static StringBuffer *monster_format_say(const object* npc, const char *message) {
2249  char name[MAX_BUF];
2250  StringBuffer *buf;
2251 
2252  query_name(npc, name, sizeof(name));
2253  buf = stringbuffer_new();
2254  stringbuffer_append_printf(buf, "%s says: %s", name, message);
2255  return buf;
2256 }
2257 
2264  switch (rt) {
2265  case rt_say:
2266  return "say";
2267  case rt_reply:
2268  return "reply";
2269  case rt_question:
2270  return "ask";
2271  }
2272  assert(0);
2273  return NULL;
2274 }
2275 
2281 static const char *get_reply_text_other(reply_type rt) {
2282  switch (rt) {
2283  case rt_say:
2284  return "says";
2285  case rt_reply:
2286  return "replies";
2287  case rt_question:
2288  return "asks";
2289  }
2290  assert(0);
2291  return NULL;
2292 }
2293 
2319 void monster_communicate(object *op, const char *txt) {
2320  int i, mflags;
2321  int16_t x, y;
2322  mapstruct *mp, *orig_map = op->map;
2323  char own[MAX_BUF], others[MAX_BUF];
2324  talk_info info;
2325 
2326  info.text = txt;
2327  info.message = NULL;
2328  info.replies_count = 0;
2329  info.who = op;
2330  info.npc_msg_count = 0;
2331 
2332  /* Note that this loop looks pretty inefficient to me - we look and try to talk
2333  * to every object within 2 spaces. It would seem that if we trim this down to
2334  * only try to talk to objects with npc->msg set, things would be a lot more efficient,
2335  * but I'm not sure if there are any objects out there that don't have a message and instead
2336  * rely sorely on events - MSW 2009-04-14
2337  */
2338  for (i = 0; i <= SIZEOFFREE2; i++) {
2339  mp = op->map;
2340  x = op->x+freearr_x[i];
2341  y = op->y+freearr_y[i];
2342 
2343  mflags = get_map_flags(mp, &mp, x, y, &x, &y);
2344  if (mflags&P_OUT_OF_MAP)
2345  continue;
2346 
2347  FOR_MAP_PREPARE(mp, x, y, npc) {
2348  monster_talk_to_npc(npc, &info);
2349  if (orig_map != op->map) {
2350  LOG(llevDebug, "Warning: Forced to swap out very recent map\n");
2351  return;
2352  }
2353  } FOR_MAP_FINISH();
2354  }
2355 
2356  /* First, what the player says. */
2357  if (info.message != NULL) {
2358  snprintf(own, sizeof(own), "You %s: %s", get_reply_text_own(info.message_type), info.message);
2359  snprintf(others, sizeof(others), "%s %s: %s", op->name, get_reply_text_other(info.message_type), info.message);
2360  free_string(info.message);
2361  } else {
2362  snprintf(own, sizeof(own), "You say: %s", txt);
2363  snprintf(others, sizeof(others), "%s says: %s", op->name, txt);
2364  }
2367 
2368  /* Then NPCs can actually talk. */
2369  for (i = 0; i < info.npc_msg_count; i++) {
2370  monster_do_say(orig_map, info.npc_msgs[i]);
2371  free_string(info.npc_msgs[i]);
2372  }
2373 
2374  /* Finally, the replies the player can use. */
2375  if (info.replies_count > 0) {
2377  for (i = 0; i < info.replies_count; i++) {
2379  free_string(info.replies_words[i]);
2380  free_string(info.replies[i]);
2381  }
2382  }
2383 }
2384 
2393 static int monster_do_talk_npc(object *npc, talk_info *info) {
2396 
2397  if (!get_dialog_message(npc, info->text, &message, &reply))
2398  return 0;
2399 
2400  if (reply) {
2401  info->message = add_string(reply->message);
2402  info->message_type = reply->type;
2403  }
2404 
2405  if (npc->type == MAGIC_EAR) {
2407  use_trigger(npc);
2408  } else {
2409  char value[2];
2410 
2411  if (info->npc_msg_count < MAX_NPC) {
2413  info->npc_msg_count++;
2414  }
2415 
2416  /* mark that the npc was talked to, so it won't move randomly later on */
2417  value[0] = '3' + rand() % 6;
2418  value[1] = '\0';
2419  object_set_value(npc, "talked_to", value, 1);
2420 
2421  reply = message->replies;
2422  while (reply && info->replies_count < MAX_REPLIES) {
2423  info->replies[info->replies_count] = add_string(reply->message);
2424  info->replies_words[info->replies_count] = add_string(reply->reply);
2425  info->replies_count++;
2426  reply = reply->next;
2427  }
2428  }
2429 
2430  return 1;
2431 }
2432 
2438 void monster_npc_say(object *npc, const char *cp) {
2439  char *message;
2441 
2443  monster_do_say(npc->map, message);
2444  free(message);
2445 }
2446 
2455 static int monster_talk_to_npc(object *npc, talk_info *info) {
2456 
2457  if (events_execute_object_say(npc, info) != 0)
2458  return 0;
2459 
2460  /* Here we let the objects inside inventories hear and answer, too. */
2461  /* This allows the existence of "intelligent" weapons you can discuss with */
2462  FOR_INV_PREPARE(npc, cobj)
2463  if (events_execute_object_say(cobj, info) != 0)
2464  return 0;
2465  FOR_INV_FINISH();
2466  if (info->who == npc)
2467  return 0;
2468  return monster_do_talk_npc(npc, info);
2469 }
2470 
2483 object *monster_find_throw_ob(object *op) {
2484  /* New throw code: look through the inventory. Grap the first legal is_thrown
2485  * marked item and throw it to the enemy.
2486  */
2487 
2488  FOR_INV_PREPARE(op, tmp) {
2489  /* Can't throw invisible objects or items that are applied */
2490  if (!tmp->invisible && !QUERY_FLAG(tmp, FLAG_APPLIED) && QUERY_FLAG(tmp, FLAG_IS_THROWN)) {
2491 #ifdef DEBUG_THROW
2492  char what[MAX_BUF];
2493 
2494  query_name(tmp, what, MAX_BUF);
2495  LOG(llevDebug, "%s chooses to throw: %s (%d)\n", op->name, what, tmp->count);
2496 #endif
2497  return tmp;
2498  }
2499  } FOR_INV_FINISH();
2500 
2501 #ifdef DEBUG_THROW
2502  LOG(llevDebug, "%s chooses to throw nothing\n", op->name);
2503 #endif
2504  return NULL;
2505 }
2506 
2522 int monster_can_detect_enemy(object *op, object *enemy, rv_vector *rv) {
2523  int radius = MIN_MON_RADIUS, hide_discovery;
2524 
2525  /* null detection for any of these condtions always */
2526  if (!op || !enemy || !op->map || !enemy->map)
2527  return 0;
2528 
2529  /* If the monster (op) has no way to get to the enemy, do nothing */
2530  if (!get_rangevector(op, enemy, rv, 0))
2531  return 0;
2532 
2533  /* Monsters always ignore the DM */
2534  if (op->type != PLAYER && QUERY_FLAG(enemy, FLAG_WIZ))
2535  return 0;
2536 
2537  /* simple check. Should probably put some range checks in here. */
2538  if (monster_can_see_enemy(op, enemy))
2539  return 1;
2540 
2541  /* The rest of this is for monsters. Players are on their own for
2542  * finding enemies!
2543  */
2544  if (op->type == PLAYER)
2545  return 0;
2546 
2547  /* Quality invisible? Bah, we wont see them w/o SEE_INVISIBLE
2548  * flag (which was already checked) in can_see_enmy (). Lets get out of here
2549  */
2550  if (enemy->invisible && (!enemy->contr || (!enemy->contr->tmp_invis && !enemy->contr->hidden)))
2551  return 0;
2552 
2553  /* use this for invis also */
2554  hide_discovery = op->stats.Int/5;
2555 
2556  /* Determine Detection radii */
2557  if (!enemy->hide) /* to detect non-hidden (eg dark/invis enemy) */
2558  radius = MAX(op->stats.Wis/5+1, MIN_MON_RADIUS);
2559  else { /* a level/INT/Dex adjustment for hiding */
2560  object *sk_hide;
2561  int bonus = (op->level/2)+(op->stats.Int/5);
2562 
2563  if (enemy->type == PLAYER) {
2564  sk_hide = find_skill_by_number(enemy, SK_HIDING);
2565  if (sk_hide != NULL)
2566  bonus -= sk_hide->level;
2567  else {
2568  LOG(llevError, "monster_can_detect_enemy() got hidden player w/o hiding skill!\n");
2569  make_visible(enemy);
2570  radius = MAX(radius, MIN_MON_RADIUS);
2571  }
2572  } else /* enemy is not a player */
2573  bonus -= enemy->level;
2574 
2575  radius += bonus/5;
2576  hide_discovery += bonus*5;
2577  } /* else creature has modifiers for hiding */
2578 
2579  /* Radii stealth adjustment. Only if you are stealthy
2580  * will you be able to sneak up closer to creatures */
2581  if (QUERY_FLAG(enemy, FLAG_STEALTH))
2582  radius = radius/2, hide_discovery = hide_discovery/3;
2583 
2584  /* Radii adjustment for enemy standing in the dark */
2585  if (op->map->darkness > 0 && !monster_stand_in_light(enemy)) {
2586  /* on dark maps body heat can help indicate location with infravision
2587  * undead don't have body heat, so no benefit detecting them.
2588  */
2589  if (QUERY_FLAG(op, FLAG_SEE_IN_DARK) && !is_true_undead(enemy))
2590  radius += op->map->darkness/2;
2591  else
2592  radius -= op->map->darkness/2;
2593 
2594  /* op next to a monster (and not in complete darkness)
2595  * the monster should have a chance to see you.
2596  */
2597  if (radius < MIN_MON_RADIUS && op->map->darkness < 5 && rv->distance <= 1)
2598  radius = MIN_MON_RADIUS;
2599  } /* if on dark map */
2600 
2601  /* Lets not worry about monsters that have incredible detection
2602  * radii, we only need to worry here about things the player can
2603  * (potentially) see. This is 13, as that is the maximum size the player
2604  * may have for their map - in that way, creatures at the edge will
2605  * do something. Note that the distance field in the
2606  * vector is real distance, so in theory this should be 18 to
2607  * find that.
2608  */
2609  if (radius > 13)
2610  radius = 13;
2611 
2612  /* Enemy in range! Now test for detection */
2613  if ((int)rv->distance <= radius) {
2614  /* ah, we are within range, detected? take cases */
2615  if (!enemy->invisible) /* enemy in dark squares... are seen! */
2616  return 1;
2617 
2618  /* hidden or low-quality invisible */
2619  if (enemy->hide && rv->distance <= 1 && RANDOM()%100 <= (unsigned int)hide_discovery) {
2620  make_visible(enemy);
2621  /* inform players of new status */
2622  if (enemy->type == PLAYER && player_can_view(enemy, op))
2624  "You are discovered by %s!",
2625  op->name);
2626  return 1; /* detected enemy */
2627  } else if (enemy->invisible) {
2628  /* Change this around - instead of negating the invisible, just
2629  * return true so that the mosnter that managed to detect you can
2630  * do something to you. Decreasing the duration of invisible
2631  * doesn't make a lot of sense IMO, as a bunch of stupid creatures
2632  * can then basically negate the spell. The spell isn't negated -
2633  * they just know where you are!
2634  */
2635  if (RANDOM()%50 <= (unsigned int)hide_discovery) {
2636  if (enemy->type == PLAYER) {
2637  char name[MAX_BUF];
2638 
2641  "You see %s noticing your position.",
2642  name);
2643  }
2644  return 1;
2645  }
2646  }
2647  } /* within range */
2648 
2649  /* Wasn't detected above, so still hidden */
2650  return 0;
2651 }
2652 
2663  int16_t nx, ny;
2664  mapstruct *m;
2665 
2666  if (!op)
2667  return 0;
2668  if (op->glow_radius > 0)
2669  return 1;
2670 
2671  if (op->map) {
2672  int x, y, x1, y1;
2673 
2674  /* Check the spaces with the max light radius to see if any of them
2675  * have lights, and if any of them light the player enough, then return 1.
2676  */
2677  for (x = op->x-MAX_LIGHT_RADII; x <= op->x+MAX_LIGHT_RADII; x++) {
2678  for (y = op->y-MAX_LIGHT_RADII; y <= op->y+MAX_LIGHT_RADII; y++) {
2679  m = op->map;
2680  nx = x;
2681  ny = y;
2682 
2683  if (get_map_flags(m, &m, nx, ny, &nx, &ny)&P_OUT_OF_MAP)
2684  continue;
2685 
2686  x1 = abs(x-op->x)*abs(x-op->x);
2687  y1 = abs(y-op->y)*abs(y-op->y);
2688  if (isqrt(x1+y1) < GET_MAP_LIGHT(m, nx, ny))
2689  return 1;
2690  }
2691  }
2692  }
2693  return 0;
2694 }
2695 
2705 int monster_can_see_enemy(object *op, object *enemy) {
2706  object *looker = HEAD(op);
2707 
2708  /* safety */
2709  if (!looker || !enemy || !QUERY_FLAG(looker, FLAG_ALIVE))
2710  return 0;
2711 
2712  /* we dont give a full treatment of xrays here (shorter range than normal,
2713  * see through walls). Should we change the code elsewhere to make you
2714  * blind even if you can xray?
2715  */
2716  if (QUERY_FLAG(looker, FLAG_BLIND) && !QUERY_FLAG(looker, FLAG_XRAYS))
2717  return 0;
2718 
2719  /* checking for invisible things */
2720  if (enemy->invisible) {
2721  /* HIDDEN ENEMY. by definition, you can't see hidden stuff!
2722  * However, if you carry any source of light, then the hidden
2723  * creature is seeable (and stupid) */
2724  if (has_carried_lights(enemy)) {
2725  if (enemy->hide) {
2726  make_visible(enemy);
2728  "Your light reveals your hiding spot!");
2729  }
2730  return 1;
2731  } else if (enemy->hide)
2732  return 0;
2733 
2734  /* Invisible enemy. Break apart the check for invis undead/invis looker
2735  * into more simple checks - the QUERY_FLAG doesn't return 1/0 values,
2736  * and making it a conditional makes the code pretty ugly.
2737  */
2738  if (!QUERY_FLAG(looker, FLAG_SEE_INVISIBLE)) {
2739  if (makes_invisible_to(enemy, looker))
2740  return 0;
2741  }
2742  } else if (looker->type == PLAYER) /* for players, a (possible) shortcut */
2743  if (player_can_view(looker, enemy))
2744  return 1;
2745 
2746  /* ENEMY IN DARK MAP. Without infravision, the enemy is not seen
2747  * unless they carry a light or stand in light. Darkness doesnt
2748  * inhibit the undead per se (but we should give their archs
2749  * CAN_SEE_IN_DARK, this is just a safety
2750  * we care about the enemy maps status, not the looker.
2751  * only relevant for tiled maps, but it is possible that the
2752  * enemy is on a bright map and the looker on a dark - in that
2753  * case, the looker can still see the enemy
2754  */
2755  if (enemy->map->darkness > 0
2756  && !monster_stand_in_light(enemy)
2757  && (!QUERY_FLAG(looker, FLAG_SEE_IN_DARK) || !is_true_undead(looker) || !QUERY_FLAG(looker, FLAG_XRAYS)))
2758  return 0;
2759 
2760  return 1;
2761 }
mapdef::height
uint16_t height
Definition: map.h:346
FLAG_USE_BOW
#define FLAG_USE_BOW
Definition: define.h:293
GET_MAP_OB
#define GET_MAP_OB(M, X, Y)
Definition: map.h:173
do_skill
int do_skill(object *op, object *part, object *skill, int dir, const char *string)
Definition: skill_util.c:422
get_weight_limit
uint32_t get_weight_limit(int stat)
Definition: living.c:2362
MAX_KNOWN_SPELLS
#define MAX_KNOWN_SPELLS
Definition: monster.c:1171
MAX_EXPLORE
#define MAX_EXPLORE
Definition: monster.c:383
TRIGGER
@ TRIGGER
Definition: object.h:129
PLAYER
@ PLAYER
Definition: object.h:107
obj::attack_movement
uint16_t attack_movement
Definition: object.h:395
path_to_player
int path_to_player(object *mon, object *pl, unsigned mindiff)
Definition: player.c:632
SP_MAGIC_MISSILE
#define SP_MAGIC_MISSILE
Definition: spells.h:85
monster_check_wakeup
static int monster_check_wakeup(object *op, object *enemy, rv_vector *rv)
Definition: monster.c:304
global.h
FLAG_NEUTRAL
#define FLAG_NEUTRAL
Definition: define.h:354
monster_npc_call_help
void monster_npc_call_help(object *op)
Definition: monster.c:1972
add_refcount
sstring add_refcount(sstring str)
Definition: shstr.c:210
SP_BOLT
#define SP_BOLT
Definition: spells.h:78
CF_HANDLE
@ CF_HANDLE
Definition: object.h:208
liv::dam
int16_t dam
Definition: living.h:46
add_string
sstring add_string(const char *str)
Definition: shstr.c:124
talk_info::replies
sstring replies[MAX_REPLIES]
Definition: dialog.h:58
object_remove
void object_remove(object *op)
Definition: object.c:1806
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Definition: define.h:728
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Definition: stringbuffer.c:57
object_set_enemy
void object_set_enemy(object *op, object *enemy)
Definition: object.c:908
NUM_BODY_LOCATIONS
#define NUM_BODY_LOCATIONS
Definition: object.h:13
obj::face
const Face * face
Definition: object.h:334
FLAG_STAND_STILL
#define FLAG_STAND_STILL
Definition: define.h:308
FLAG_CONFUSED
#define FLAG_CONFUSED
Definition: define.h:311
AP_APPLY
#define AP_APPLY
Definition: define.h:574
BOW
@ BOW
Definition: object.h:118
WAITATT
#define WAITATT
Definition: define.h:495
llevError
@ llevError
Definition: logger.h:11
FABS
#define FABS(x)
Definition: define.h:22
monster_check_good_weapon
static int monster_check_good_weapon(object *who, object *item)
Definition: monster.c:1612
find_skill_by_number
object * find_skill_by_number(object *who, int skillno)
Definition: main.c:376
SP_BOMB
#define SP_BOMB
Definition: spells.h:82
WAND
@ WAND
Definition: object.h:220
FLAG_USE_RING
#define FLAG_USE_RING
Definition: define.h:297
ALLRUN
#define ALLRUN
Definition: define.h:497
talk_info::replies_words
sstring replies_words[MAX_REPLIES]
Definition: dialog.h:57
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
talk_info::npc_msg_count
int npc_msg_count
Definition: dialog.h:59
CAN_APPLY_NOT_MASK
#define CAN_APPLY_NOT_MASK
Definition: define.h:630
monster_use_scroll
static int monster_use_scroll(object *head, object *part, object *pl, int dir)
Definition: monster.c:1312
FLAG_GENERATOR
#define FLAG_GENERATOR
Definition: define.h:248
diamondslots.x
x
Definition: diamondslots.py:15
obj::count
tag_t count
Definition: object.h:300
RUNATT
#define RUNATT
Definition: define.h:493
obj::map
struct mapdef * map
Definition: object.h:298
MSG_TYPE_SKILL
#define MSG_TYPE_SKILL
Definition: newclient.h:407
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
monster_apply_below
static void monster_apply_below(object *monster)
Definition: monster.c:1936
PACEV2
#define PACEV2
Definition: define.h:526
pets_should_arena_attack
int pets_should_arena_attack(object *pet, object *owner, object *target)
Definition: pets.c:1084
liv::wc
int8_t wc
Definition: living.h:37
path_data
Definition: monster.c:388
make_visible
void make_visible(object *op)
Definition: player.c:3909
monster_check_enemy
object * monster_check_enemy(object *npc, rv_vector *rv)
Definition: monster.c:72
WILL_APPLY_HANDLE
#define WILL_APPLY_HANDLE
Definition: object.h:52
liv::Str
int8_t Str
Definition: living.h:36
FLAG_SEE_IN_DARK
#define FLAG_SEE_IN_DARK
Definition: define.h:337
monster_check_apply
static void monster_check_apply(object *mon, object *item)
Definition: monster.c:1694
AT_PHYSICAL
#define AT_PHYSICAL
Definition: attack.h:76
cast_spell
int cast_spell(object *op, object *caster, int dir, object *spell_ob, char *stringarg)
Definition: spell_util.c:1420
obj::attacked_by_count
tag_t attacked_by_count
Definition: object.h:387
FOR_BELOW_PREPARE
#define FOR_BELOW_PREPARE(op_, it_)
Definition: define.h:702
GEM
@ GEM
Definition: object.h:167
pl
Definition: player.h:92
monster_run_att
static int monster_run_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv)
Definition: monster.c:2018
HITRUN
#define HITRUN
Definition: define.h:494
monster_choose_random_spell
static object * monster_choose_random_spell(object *monster)
Definition: monster.c:1188
monster_get_armour_quality
static int monster_get_armour_quality(const object *item)
Definition: monster.c:1638
WEAPON
@ WEAPON
Definition: object.h:119
obj::invisible
int16_t invisible
Definition: object.h:363
MinHeap
Definition: minheap.h:18
guildjoin.ob
ob
Definition: guildjoin.py:42
say.reply
string reply
Definition: say.py:77
SP_CONE
#define SP_CONE
Definition: spells.h:81
commongive.inv
inv
Definition: commongive.py:28
FLAG_SEE_INVISIBLE
#define FLAG_SEE_INVISIBLE
Definition: define.h:253
MIN
#define MIN(x, y)
Definition: compat.h:21
TREASURE
@ TREASURE
Definition: object.h:110
talk_info::who
struct obj * who
Definition: dialog.h:52
SKILL
@ SKILL
Definition: object.h:143
object_find_by_type_applied
object * object_find_by_type_applied(const object *who, int type)
Definition: object.c:4091
FLAG_SCARED
#define FLAG_SCARED
Definition: define.h:271
ob_blocked
int ob_blocked(const object *ob, mapstruct *m, int16_t x, int16_t y)
Definition: map.c:498
monster_use_range
static int monster_use_range(object *head, object *part, object *pl, int dir)
Definition: monster.c:1453
Ice.tmp
int tmp
Definition: Ice.py:207
FLAG_ONLY_ATTACK
#define FLAG_ONLY_ATTACK
Definition: define.h:310
FLAG_READY_SCROLL
#define FLAG_READY_SCROLL
Definition: define.h:324
NDI_NAVY
#define NDI_NAVY
Definition: newclient.h:244
RANDO
#define RANDO
Definition: define.h:520
remove_friendly_object
void remove_friendly_object(object *op)
Definition: friend.c:56
llevMonster
@ llevMonster
Definition: logger.h:14
monster_use_bow
static int monster_use_bow(object *head, object *part, object *pl, int dir)
Definition: monster.c:1529
ATNR_PHYSICAL
#define ATNR_PHYSICAL
Definition: attack.h:49
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
get_rangevector
int get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags)
Definition: map.c:2535
ext_info_map
void ext_info_map(int color, const mapstruct *map, uint8_t type, uint8_t subtype, const char *str1)
Definition: main.c:335
obj::body_info
int8_t body_info[NUM_BODY_LOCATIONS]
Definition: object.h:376
skills.h
rv_vector::part
object * part
Definition: map.h:384
monster_move_randomly
static int monster_move_randomly(object *op)
Definition: monster.c:350
apply_manual
int apply_manual(object *op, object *tmp, int aflag)
Definition: apply.c:597
FOR_OB_AND_ABOVE_FINISH
#define FOR_OB_AND_ABOVE_FINISH()
Definition: define.h:741
P_IS_ALIVE
#define P_IS_ALIVE
Definition: map.h:238
FLAG_APPLIED
#define FLAG_APPLIED
Definition: define.h:235
talk_info::message_type
int message_type
Definition: dialog.h:55
FLAG_STEALTH
#define FLAG_STEALTH
Definition: define.h:312
FLAG_BLIND
#define FLAG_BLIND
Definition: define.h:336
monster_check_apply_all
void monster_check_apply_all(object *monster)
Definition: monster.c:1959
monster_get_weapon_quality
static int monster_get_weapon_quality(const object *item)
Definition: monster.c:1586
monster_should_cast_spell
static int monster_should_cast_spell(object *spell_ob)
Definition: monster.c:1148
monster_npc_say
void monster_npc_say(object *npc, const char *cp)
Definition: monster.c:2438
isqrt
int isqrt(int n)
Definition: utils.c:586
PACEH
#define PACEH
Definition: define.h:514
MAX
#define MAX(x, y)
Definition: compat.h:24
get_nearest_player
object * get_nearest_player(object *mon)
Definition: player.c:523
freearr_x
short freearr_x[SIZEOFFREE]
Definition: object.c:288
freearr_y
short freearr_y[SIZEOFFREE]
Definition: object.c:294
talk_info::message
sstring message
Definition: dialog.h:54
FOR_BELOW_FINISH
#define FOR_BELOW_FINISH()
Definition: define.h:709
talk_info::replies_count
int replies_count
Definition: dialog.h:56
FLAG_ALIVE
#define FLAG_ALIVE
Definition: define.h:230
animate_object
void animate_object(object *op, int dir)
Definition: anim.c:43
rv_vector::distance_y
int distance_y
Definition: map.h:382
FOR_OB_AND_ABOVE_PREPARE
#define FOR_OB_AND_ABOVE_PREPARE(op_)
Definition: define.h:737
object_get_value
const char * object_get_value(const object *op, const char *const key)
Definition: object.c:4354
obj::chosen_skill
struct obj * chosen_skill
Definition: object.h:390
SP_SUMMON_MONSTER
#define SP_SUMMON_MONSTER
Definition: spells.h:101
free_string
void free_string(sstring str)
Definition: shstr.c:280
m
static event_registration m
Definition: citylife.cpp:425
obj::attacked_by
struct obj * attacked_by
Definition: object.h:386
rv_vector::distance_x
int distance_x
Definition: map.h:381
monster_check_earthwalls
void monster_check_earthwalls(object *op, mapstruct *m, int x, int y)
Definition: monster.c:2207
autojail.who
who
Definition: autojail.py:3
has_carried_lights
int has_carried_lights(const object *op)
Definition: los.c:315
FLAG_NO_ATTACK
#define FLAG_NO_ATTACK
Definition: define.h:355
object_find_by_type_subtype
object * object_find_by_type_subtype(const object *who, int type, int subtype)
Definition: object.c:4309
monster_stand_in_light
int monster_stand_in_light(object *op)
Definition: monster.c:2662
SP_BULLET
#define SP_BULLET
Definition: spells.h:79
disinfect.map
map
Definition: disinfect.py:4
pets_get_enemy
object * pets_get_enemy(object *pet, rv_vector *rv)
Definition: pets.c:54
obj::name
sstring name
Definition: object.h:312
minheap.h
minheap_remove
void * minheap_remove(MinHeap *heap)
Definition: minheap.c:203
pl::tmp_invis
uint32_t tmp_invis
Definition: player.h:127
query_name
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:584
stringbuffer_finish_shared
sstring stringbuffer_finish_shared(StringBuffer *sb)
Definition: stringbuffer.c:85
FLAG_USE_RANGE
#define FLAG_USE_RANGE
Definition: define.h:292
mon
object * mon
Definition: comet_perf.c:75
FLAG_RUN_AWAY
#define FLAG_RUN_AWAY
Definition: define.h:280
monster_do_say
void monster_do_say(const mapstruct *map, const char *message)
Definition: monster.c:2237
MOVE_WALK
#define MOVE_WALK
Definition: define.h:392
minheap_insert
int minheap_insert(MinHeap *heap, void *ob)
Definition: minheap.c:181
get_reply_text_own
const char * get_reply_text_own(reply_type rt)
Definition: monster.c:2263
get_randomized_dir
int get_randomized_dir(int dir)
Definition: utils.c:439
monster_talk_to_npc
static int monster_talk_to_npc(object *npc, talk_info *info)
Definition: monster.c:2455
monster_format_say
static StringBuffer * monster_format_say(const object *npc, const char *message)
Definition: monster.c:2248
monster_do_talk_npc
static int monster_do_talk_npc(object *npc, talk_info *info)
Definition: monster.c:2393
HEAD
#define HEAD(op)
Definition: object.h:594
minheap_init_static
void minheap_init_static(MinHeap *heap, void **arr, int amt, int(*measure_func)(const void *))
Definition: minheap.c:162
fatal
void fatal(enum fatal_error err)
Definition: utils.c:597
monster_hitrun_att
static int monster_hitrun_att(int dir, object *ob)
Definition: monster.c:2033
ROD
@ ROD
Definition: object.h:109
object_can_pick
int object_can_pick(const object *who, const object *item)
Definition: object.c:3875
monster_move
int monster_move(object *op)
Definition: monster.c:823
obj::hide
uint8_t hide
Definition: object.h:391
NDI_DELAYED
#define NDI_DELAYED
Definition: newclient.h:269
monster_pace2_movev
static void monster_pace2_movev(object *ob)
Definition: monster.c:2157
FLAG_FREED
#define FLAG_FREED
Definition: define.h:233
SPELL_GRACE
#define SPELL_GRACE
Definition: spells.h:59
monster_circ2_move
static void monster_circ2_move(object *ob)
Definition: monster.c:2118
path_data::movement_penalty
int16_t movement_penalty
Definition: monster.c:394
monster_check_doors
void monster_check_doors(object *op, mapstruct *m, int x, int y)
Definition: monster.c:2223
AP_IGNORE_CURSE
#define AP_IGNORE_CURSE
Definition: define.h:582
absdir
int absdir(int d)
Definition: object.c:3722
monster_compute_path
int monster_compute_path(object *source, object *target, int default_dir)
Definition: monster.c:438
path_data::x
int16_t x
Definition: monster.c:389
struct_dialog_reply
Definition: dialog.h:18
obj::carrying
int32_t carrying
Definition: object.h:370
MAX_NPC
#define MAX_NPC
Definition: dialog.h:46
CIRCLE2
#define CIRCLE2
Definition: define.h:513
obj::x
int16_t x
Definition: object.h:328
SP_SMITE
#define SP_SMITE
Definition: spells.h:84
fix_object
void fix_object(object *op)
Definition: living.c:1126
FLAG_PARALYZED
#define FLAG_PARALYZED
Definition: define.h:371
stringbuffer_finish
char * stringbuffer_finish(StringBuffer *sb)
Definition: stringbuffer.c:76
FLAG_USE_SHIELD
#define FLAG_USE_SHIELD
Definition: define.h:237
mapdef::darkness
uint8_t darkness
Definition: map.h:345
rt_say
@ rt_say
Definition: dialog.h:10
GET_MAP_MOVE_BLOCK
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Definition: map.h:193
FOR_INV_FINISH
#define FOR_INV_FINISH()
Definition: define.h:675
GOLEM
@ GOLEM
Definition: object.h:145
apply_can_apply_object
int apply_can_apply_object(const object *who, const object *op)
Definition: apply.c:1016
object_set_value
int object_set_value(object *op, const char *key, const char *value, int add_key)
Definition: object.c:4489
sstring
const typedef char * sstring
Definition: global.h:40
FLAG_UNAGGRESSIVE
#define FLAG_UNAGGRESSIVE
Definition: define.h:272
FLAG_USE_WEAPON
#define FLAG_USE_WEAPON
Definition: define.h:296
sproto.h
ARROW
@ ARROW
Definition: object.h:117
IS_SHIELD
#define IS_SHIELD(op)
Definition: define.h:170
GET_MAP_LIGHT
#define GET_MAP_LIGHT(M, X, Y)
Definition: map.h:166
FLAG_CAN_USE_SKILL
#define FLAG_CAN_USE_SKILL
Definition: define.h:321
monster_can_see_enemy
int monster_can_see_enemy(object *op, object *enemy)
Definition: monster.c:2705
rt_reply
@ rt_reply
Definition: dialog.h:11
PACEV
#define PACEV
Definition: define.h:524
monster_communicate
void monster_communicate(object *op, const char *txt)
Definition: monster.c:2319
obj::enemy
struct obj * enemy
Definition: object.h:385
mapdef
Definition: map.h:324
SP_level_spellpoint_cost
int16_t SP_level_spellpoint_cost(object *caster, object *spell, int flags)
Definition: spell_util.c:235
monster_can_hit
static int monster_can_hit(object *ob1, object *ob2, rv_vector *rv)
Definition: monster.c:1105
RING
@ RING
Definition: object.h:185
liv::Int
int8_t Int
Definition: living.h:36
obj::animation
const Animations * animation
Definition: object.h:420
nlohmann::detail::void
j template void())
Definition: json.hpp:4099
LO4
#define LO4
Definition: define.h:530
FLAG_MONSTER
#define FLAG_MONSTER
Definition: define.h:245
FLAG_RANDOM_MOVE
#define FLAG_RANDOM_MOVE
Definition: define.h:309
SIZEOFFREE
#define SIZEOFFREE
Definition: define.h:155
P_OUT_OF_MAP
#define P_OUT_OF_MAP
Definition: map.h:250
MAX_BUF
#define MAX_BUF
Definition: define.h:35
obj::spellitem
struct obj * spellitem
Definition: object.h:398
monster_do_living
void monster_do_living(object *op)
Definition: monster.c:688
MSG_TYPE_DIALOG
#define MSG_TYPE_DIALOG
Definition: newclient.h:400
IS_WEAPON
#define IS_WEAPON(op)
Definition: define.h:163
talk_info::text
const char * text
Definition: dialog.h:53
pets_move
void pets_move(object *ob)
Definition: pets.c:315
RANDOM
#define RANDOM()
Definition: define.h:642
HI4
#define HI4
Definition: define.h:531
move_object
int move_object(object *op, int dir)
Definition: move.c:39
SK_HIDING
@ SK_HIDING
Definition: skills.h:21
StringBuffer
Definition: stringbuffer.c:25
MOVE_FLY_LOW
#define MOVE_FLY_LOW
Definition: define.h:393
SP_MAGIC_WALL
#define SP_MAGIC_WALL
Definition: spells.h:89
monster_check_good_armour
static int monster_check_good_armour(object *who, object *item)
Definition: monster.c:1659
guildbuy.ob2
ob2
Definition: guildbuy.py:23
is_valid_types_gen.found
found
Definition: is_valid_types_gen.py:39
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:721
obj::y
int16_t y
Definition: object.h:328
SP_INVISIBLE
#define SP_INVISIBLE
Definition: spells.h:93
OUT_OF_REAL_MAP
#define OUT_OF_REAL_MAP(M, X, Y)
Definition: map.h:218
dirdiff
int dirdiff(int dir1, int dir2)
Definition: object.c:3740
monster_use_skill
static int monster_use_skill(object *head, object *part, object *pl, int dir)
Definition: monster.c:1396
MAGIC_EAR
@ MAGIC_EAR
Definition: object.h:131
obj::arch
struct archt * arch
Definition: object.h:416
monster_dist_att
static int monster_dist_att(int dir, object *enemy, object *part, rv_vector *rv)
Definition: monster.c:1999
diamondslots.message
string message
Definition: diamondslots.py:57
FLAG_READY_SKILL
#define FLAG_READY_SKILL
Definition: define.h:333
FLAG_READY_BOW
#define FLAG_READY_BOW
Definition: define.h:299
FLAG_REMOVED
#define FLAG_REMOVED
Definition: define.h:232
path_data::y
int16_t y
Definition: monster.c:390
reply_type
reply_type
Definition: dialog.h:9
get_reply_text_other
static const char * get_reply_text_other(reply_type rt)
Definition: monster.c:2281
FLAG_WIZ
#define FLAG_WIZ
Definition: define.h:231
ext_info_map_except
void ext_info_map_except(int color, const mapstruct *map, const object *op, uint8_t type, uint8_t subtype, const char *str1)
Definition: info.c:218
obj::type
uint8_t type
Definition: object.h:341
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:262
monster_pace_movev
static void monster_pace_movev(object *ob)
Definition: monster.c:2131
FLAG_FRIENDLY
#define FLAG_FRIENDLY
Definition: define.h:246
spells.h
guildbuy.ob1
ob1
Definition: guildbuy.py:22
struct_dialog_message
Definition: dialog.h:28
obj::stats
living stats
Definition: object.h:371
MSG_TYPE_SKILL_FAILURE
#define MSG_TYPE_SKILL_FAILURE
Definition: newclient.h:590
obj::direction
int8_t direction
Definition: object.h:337
path_data::distance
uint16_t distance
Definition: monster.c:391
archt::clone
object clone
Definition: object.h:472
SIZEOFFREE2
#define SIZEOFFREE2
Definition: define.h:154
obj::contr
struct pl * contr
Definition: object.h:277
obj::facing
int8_t facing
Definition: object.h:338
MAX_REPLIES
#define MAX_REPLIES
Definition: dialog.h:44
use_trigger
void use_trigger(object *op)
Definition: button.c:254
obj::weight
int32_t weight
Definition: object.h:368
IS_ARMOR
#define IS_ARMOR(op)
Definition: define.h:166
FLAG_USE_ARMOUR
#define FLAG_USE_ARMOUR
Definition: define.h:295
item
Definition: item.py:1
FLAG_CAST_SPELL
#define FLAG_CAST_SPELL
Definition: define.h:290
EARTHWALL
@ EARTHWALL
Definition: object.h:144
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
path_measure_func
int path_measure_func(const void *ob)
Definition: monster.c:406
SP_MOVING_BALL
#define SP_MOVING_BALL
Definition: spells.h:109
liv::Wis
int8_t Wis
Definition: living.h:36
liv::grace
int16_t grace
Definition: living.h:44
monster_find_nearest_living_creature
object * monster_find_nearest_living_creature(object *npc, object *exclude)
Definition: monster.c:155
rt_question
@ rt_question
Definition: dialog.h:12
give.op
op
Definition: give.py:33
autojail.value
value
Definition: autojail.py:6
monster_can_pick
static int monster_can_pick(object *monster, object *item)
Definition: monster.c:1855
pets_follow_owner
void pets_follow_owner(object *ob, object *owner)
Definition: pets.c:282
rv_vector
Definition: map.h:379
get_dialog_message
int get_dialog_message(object *op, const char *text, struct_dialog_message **message, struct_dialog_reply **reply)
Definition: dialog.c:209
hit_player
int hit_player(object *op, int dam, object *hitter, uint32_t type, int full_hit)
Definition: attack.c:1853
do_hidden_move
void do_hidden_move(object *op)
Definition: player.c:3994
diamondslots.y
y
Definition: diamondslots.py:16
NDI_WHITE
#define NDI_WHITE
Definition: newclient.h:243
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
buf
StringBuffer * buf
Definition: readable.c:1606
AP_NOPRINT
#define AP_NOPRINT
Definition: define.h:585
talk_info
Definition: dialog.h:51
pl::hidden
uint32_t hidden
Definition: player.h:134
stringbuffer_append_printf
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
Definition: stringbuffer.c:104
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
Definition: object.c:2820
guild_entry.x1
int x1
Definition: guild_entry.py:33
MSG_TYPE_DIALOG_MAGIC_EAR
#define MSG_TYPE_DIALOG_MAGIC_EAR
Definition: newclient.h:489
obj::head
struct obj * head
Definition: object.h:297
obj::subtype
uint8_t subtype
Definition: object.h:342
obj::more
struct obj * more
Definition: object.h:296
MSG_TYPE_DIALOG_NPC
#define MSG_TYPE_DIALOG_NPC
Definition: newclient.h:487
obj::move_type
MoveType move_type
Definition: object.h:428
fire_bow
int fire_bow(object *op, object *arrow, int dir, int wc_mod, int16_t sx, int16_t sy)
Definition: player.c:2069
monster_find_enemy
static object * monster_find_enemy(object *npc, rv_vector *rv)
Definition: monster.c:217
talk_info::npc_msgs
sstring npc_msgs[MAX_NPC]
Definition: dialog.h:60
npc_dialog.npc
npc
Definition: npc_dialog.py:95
make_face_from_files.int
int
Definition: make_face_from_files.py:26
MIN_ACTIVE_SPEED
#define MIN_ACTIVE_SPEED
Definition: define.h:637
estimate_distance
static uint16_t estimate_distance(int16_t ax, int16_t ay, int16_t bx, int16_t by)
Definition: monster.c:416
obj::pick_up
uint8_t pick_up
Definition: object.h:364
monster_rand_move
static void monster_rand_move(object *ob)
Definition: monster.c:2187
draw_ext_info
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: main.c:309
FLAG_BERSERK
#define FLAG_BERSERK
Definition: define.h:352
get_attr_value
int8_t get_attr_value(const living *stats, int attr)
Definition: living.c:314
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.c:1533
FOOD
@ FOOD
Definition: object.h:112
monster_wait_att
static int monster_wait_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv)
Definition: monster.c:2051
DOOR
@ DOOR
Definition: object.h:126
player_can_view
int player_can_view(object *pl, object *op)
Definition: player.c:4103
object_find_by_type_and_race
object * object_find_by_type_and_race(const object *who, int type, const char *race)
Definition: object.c:4141
FLAG_UNPAID
#define FLAG_UNPAID
Definition: define.h:236
monster_circ1_move
static void monster_circ1_move(object *ob)
Definition: monster.c:2105
SP_SUMMON_GOLEM
#define SP_SUMMON_GOLEM
Definition: spells.h:86
monster_can_detect_enemy
int monster_can_detect_enemy(object *op, object *enemy, rv_vector *rv)
Definition: monster.c:2522
WAIT2
#define WAIT2
Definition: define.h:499
path_data::heuristic_dist
uint16_t heuristic_dist
Definition: monster.c:392
FLAG_READY_RANGE
#define FLAG_READY_RANGE
Definition: define.h:298
SCROLL
@ SCROLL
Definition: object.h:221
DISTHIT
#define DISTHIT
Definition: define.h:498
FLAG_XRAYS
#define FLAG_XRAYS
Definition: define.h:300
RUSH
#define RUSH
Definition: define.h:496
monster_check_pickup
static void monster_check_pickup(object *monster)
Definition: monster.c:1811
PETMOVE
#define PETMOVE
Definition: define.h:501
monster_move_no_enemy
static int monster_move_no_enemy(object *op)
Definition: monster.c:751
obj::will_apply
uint8_t will_apply
Definition: object.h:396
MSG_TYPE_COMMUNICATION
#define MSG_TYPE_COMMUNICATION
Definition: newclient.h:410
drain_rod_charge
void drain_rod_charge(object *rod)
Definition: spell_util.c:775
DISTATT
#define DISTATT
Definition: define.h:491
WILL_APPLY_TREASURE
#define WILL_APPLY_TREASURE
Definition: object.h:53
monster_pace_moveh
static void monster_pace_moveh(object *ob)
Definition: monster.c:2144
mapdef::path
char path[HUGE_BUF]
Definition: map.h:364
get_map_flags
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
Definition: map.c:311
get_search_arr
void get_search_arr(int *search_arr)
Definition: object.c:3592
SPELL
@ SPELL
Definition: object.h:214
events_execute_object_say
int events_execute_object_say(object *npc, talk_info *talk)
Definition: events.cpp:263
replace.current
current
Definition: replace.py:64
monster_find_throw_ob
object * monster_find_throw_ob(object *op)
Definition: monster.c:2483
liv::sp
int16_t sp
Definition: living.h:42
monster_pace2_moveh
static void monster_pace2_moveh(object *ob)
Definition: monster.c:2172
SP_SWARM
#define SP_SWARM
Definition: spells.h:110
monster_wait_att2
static int monster_wait_att2(int dir, rv_vector *rv)
Definition: monster.c:2095
OUT_OF_MEMORY
@ OUT_OF_MEMORY
Definition: define.h:48
FLAG_USE_SCROLL
#define FLAG_USE_SCROLL
Definition: define.h:291
mapdef::width
uint16_t width
Definition: map.h:346
CIRCLE1
#define CIRCLE1
Definition: define.h:509
rv_vector::direction
int direction
Definition: map.h:383
makes_invisible_to
int makes_invisible_to(object *pl, object *mon)
Definition: spell_effect.c:764
monster_cast_spell
static int monster_cast_spell(object *head, object *part, object *pl, int dir)
Definition: monster.c:1226
on_same_map
int on_same_map(const object *op1, const object *op2)
Definition: map.c:2647
PACEH2
#define PACEH2
Definition: define.h:516
SP_EXPLOSION
#define SP_EXPLOSION
Definition: spells.h:80
obj::resist
int16_t resist[NROFATTACKS]
Definition: object.h:344
FLAG_IS_THROWN
#define FLAG_IS_THROWN
Definition: define.h:249
THROWN_OBJ
@ THROWN_OBJ
Definition: object.h:146
get_map_from_coord
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
Definition: map.c:2375
FLAG_SLEEP
#define FLAG_SLEEP
Definition: define.h:307
SK_THROWING
@ SK_THROWING
Definition: skills.h:44
object_split
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
Definition: object.c:2600
guild_entry.y1
int y1
Definition: guild_entry.py:34
rv_vector::distance
unsigned int distance
Definition: map.h:380
SPELLBOOK
@ SPELLBOOK
Definition: object.h:203
NUM_STATS
@ NUM_STATS
Definition: living.h:18
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:668
MSG_TYPE_COMMUNICATION_SAY
#define MSG_TYPE_COMMUNICATION_SAY
Definition: newclient.h:623
drain_wand_charge
void drain_wand_charge(object *wand)
Definition: spell_util.c:785
monster_disthit_att
static int monster_disthit_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv)
Definition: monster.c:2076
can_see_monsterP
int can_see_monsterP(mapstruct *m, int x, int y, int dir)
Definition: object.c:3830
MAX_LIGHT_RADII
#define MAX_LIGHT_RADII
Definition: define.h:450
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Definition: main.c:319
obj::level
int16_t level
Definition: object.h:354
WILL_APPLY_FOOD
#define WILL_APPLY_FOOD
Definition: object.h:56
llevDebug
@ llevDebug
Definition: logger.h:13
MONEY
@ MONEY
Definition: object.h:137
obj::range
int8_t range
Definition: object.h:409
RANDO2
#define RANDO2
Definition: define.h:523
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Definition: define.h:302
is_true_undead
int is_true_undead(object *op)
Definition: player.c:3929
obj::inv
struct obj * inv
Definition: object.h:291
give.name
name
Definition: give.py:27
MIN_MON_RADIUS
#define MIN_MON_RADIUS
Definition: monster.c:56
skill_attack
void skill_attack(object *tmp, object *pl, int dir, const char *string, object *skill)
Definition: skill_util.c:1272
SPELL_MANA
#define SPELL_MANA
Definition: spells.h:58
object_get_owner
object * object_get_owner(object *op)
Definition: object.c:797