Crossfire Server, Trunk
monster.cpp
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 && !object_value_set(npc, "is_guard")) {
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 
142 static int is_enemy(object *who, object *owner) {
143  if (who == owner) {
144  return 0;
145  }
146  if (!QUERY_FLAG(who, FLAG_MONSTER) && !QUERY_FLAG(who, FLAG_GENERATOR) && who->type != PLAYER) {
147  return 0;
148  }
149  if (QUERY_FLAG(who, FLAG_MONSTER) && owner && object_get_owner(who) == owner) {
150  return 0;
151  }
152  if (who->type == PLAYER && owner && owner->type == PLAYER) {
153  if (owner->contr->peaceful && who->contr->peaceful) {
154  return 0;
155  }
156  }
157  return 1;
158 }
159 
175 object *monster_find_nearest_enemy(object *npc, object *owner) {
176  int i, mflags;
177  int16_t nx, ny;
178  mapstruct *m;
179  int search_arr[SIZEOFFREE];
180 
181  get_search_arr(search_arr);
182  for (i = 0; i < SIZEOFFREE; i++) {
183  /* modified to implement smart searching using search_arr
184  * guidance array to determine direction of search order
185  */
186  nx = npc->x+freearr_x[search_arr[i]];
187  ny = npc->y+freearr_y[search_arr[i]];
188  m = npc->map;
189 
190  if (nx == npc->x && ny == npc->y) {
191  continue; // Don't try to attack ourself
192  }
193 
194  mflags = get_map_flags(m, &m, nx, ny, &nx, &ny);
195  if (mflags&P_OUT_OF_MAP)
196  continue;
197 
198  if (mflags&P_IS_ALIVE) {
199  object *creature = NULL;
200  FOR_MAP_PREPARE(m, nx, ny, tmp)
201  if (is_enemy(tmp, owner)) {
202  creature = tmp;
203  break;
204  }
205  FOR_MAP_FINISH();
206  // it is possible to not find an enemy even if the square is alive,
207  // e.g. the npc's owner is there
208  if (creature) {
209  if (can_see_monsterP(m, npc->x, npc->y, i))
210  return creature;
211  }
212  } /* is something living on this space */
213  }
214  return NULL; /* nothing found */
215 }
216 
232 static object *monster_find_enemy(object *npc, rv_vector *rv) {
233  object *attacker, *tmp = NULL;
234 
235  attacker = npc->attacked_by; /* save this for later use. This can be a attacker. */
236  npc->attacked_by = NULL; /* always clear the attacker entry */
237 
238  /* if we berserk, we don't care about others - we attack all we can find */
239  if (QUERY_FLAG(npc, FLAG_BERSERK)) {
241  if (tmp == NULL)
242  return NULL;
243  if (!get_rangevector(npc, tmp, rv, 0))
244  return NULL;
245  return tmp;
246  }
247 
248  /* Here is the main enemy selection.
249  * We want this: if there is an enemy, attack him until its not possible or
250  * one of both is dead.
251  * If we have no enemy and we are...
252  * a monster: try to find a player, a pet or a friendly monster
253  * a friendly: only target a monster which is targeting you first or targeting a player
254  * a neutral: fight a attacker (but there should be none), then do nothing
255  * a pet: attack player enemy or a monster
256  */
257 
258  /* pet move */
259  if ((npc->attack_movement&HI4) == PETMOVE) {
260  tmp = pets_get_enemy(npc, rv);
261  if (tmp == NULL)
262  return NULL;
263  if (!get_rangevector(npc, tmp, rv, 0))
264  return NULL;
265  return tmp;
266  }
267 
268  /* we check our old enemy. */
269  tmp = monster_check_enemy(npc, rv);
270  if (tmp == NULL) {
271  if (attacker) { /* if we have an attacker, check him */
272  /* we want be sure this is the right one! */
273  if (attacker->count == npc->attacked_by_count) {
274  /* TODO: thats not finished */
275  /* we don't want a fight evil vs evil or good against non evil */
277  || QUERY_FLAG(attacker, FLAG_NEUTRAL) /* neutral */
279  || (!QUERY_FLAG(npc, FLAG_FRIENDLY) && (!QUERY_FLAG(attacker, FLAG_FRIENDLY) && attacker->type != PLAYER)))
280  CLEAR_FLAG(npc, FLAG_SLEEP); /* skip it, but lets wakeup */
281  else if (on_same_map(npc, attacker)) { /* thats the only thing we must know... */
282  CLEAR_FLAG(npc, FLAG_SLEEP); /* well, NOW we really should wake up! */
283  object_set_enemy(npc, attacker);
284  if (!get_rangevector(npc, attacker, rv, 0))
285  return NULL;
286  return attacker; /* yes, we face our attacker! */
287  }
288  }
289  }
290 
291  if (object_value_set(npc, "is_guard")) {
293  if (npc->enemy) {
294  char buf[MAX_BUF];
295  snprintf(buf, sizeof(buf), "Halt, %s, you are under arrest!", npc->enemy->name);
297  tmp = monster_check_enemy(npc, rv);
298  }
299  } else {
300  /* we have no legal enemy or attacker, so we try to target a new one */
303  && !QUERY_FLAG(npc, FLAG_NEUTRAL)) {
305  if (npc->enemy)
306  tmp = monster_check_enemy(npc, rv);
307  }
308  }
309  }
310 
311  return tmp;
312 }
313 
329 static int monster_check_wakeup(object *op, object *enemy, rv_vector *rv) {
330  int radius = MAX(op->stats.Wis, MIN_MON_RADIUS);
331 
332  /* Trim work - if no enemy, no need to do anything below */
333  if (!enemy)
334  return 0;
335 
336  /* blinded monsters can only find nearby objects to attack */
337  if (QUERY_FLAG(op, FLAG_BLIND))
338  radius = MIN_MON_RADIUS;
339 
340  /* This covers the situation where the monster is in the dark
341  * and has an enemy. If the enemy has no carried light (or isnt
342  * glowing!) then the monster has trouble finding the enemy.
343  * Remember we already checked to see if the monster can see in
344  * the dark. */
345  else if (op->map
346  && op->map->darkness > 0
347  && enemy
348  && !enemy->invisible
349  && !monster_stand_in_light(enemy)
351  int dark = radius/(op->map->darkness);
352 
353  radius = (dark > MIN_MON_RADIUS) ? (dark+1) : MIN_MON_RADIUS;
354  } else if (!QUERY_FLAG(op, FLAG_SLEEP))
355  return 1;
356 
357  /* enemy should already be on this map, so don't really need to check
358  * for that.
359  */
360  if (rv->distance < (unsigned)(QUERY_FLAG(enemy, FLAG_STEALTH) ? radius/2+1 : radius)) {
362  return 1;
363  }
364  return 0;
365 }
366 
375 static int monster_move_randomly(object *op) {
376  int i;
377  sstring talked;
378  char value[2];
379 
380  /* timeout before moving */
382  talked = object_get_value(op, "talked_to");
383  if (talked && strlen(talked) > 0) {
384  i = atoi(talked);
385  i--;
386 
387  if (i != 0) {
388  value[1] = '\0';
389  value[0] = '0' + i;
390  object_set_value(op, "talked_to", value, 1);
391  return 1;
392  }
393 
394  /* finished timeout talked to */
395  object_set_value(op, "talked_to", "", 1);
396  }
397  }
398 
399  /* Give up to 15 chances for a monster to move randomly */
400  for (i = 0; i < 15; i++) {
401  if (move_object(op, RANDOM()%8+1))
402  return 1;
403  }
404  return 0;
405 }
406 
408 #define MAX_EXPLORE 5000
409 
413 struct path_data {
414  int16_t x;
415  int16_t y;
416  uint16_t distance;
417  uint16_t heuristic_dist;
418  // This way we only have to calculate penalties once per tile per pathing calculation.
420 };
421 
431 int path_measure_func(const void *ob) {
432  const path_data *dat = (path_data *)ob;
433  return dat->distance + dat->heuristic_dist;
434 }
435 
441 static inline uint16_t estimate_distance(int16_t ax, int16_t ay, int16_t bx, int16_t by) {
442  uint16_t dx = FABS(ax - bx), dy = FABS(ay - by);
443  uint16_t diag = MIN(dx, dy);
444  return (MAX(dx, dy) - diag) * 2 + diag * 3;
445 }
446 
463 int monster_compute_path(object *source, object *target, int default_dir) {
464  path_data *distance, *current, *explore;
465  path_data *heaparr[MAX_EXPLORE];
466  int dirs[8];
467  int dir, x, y, i;
468  MinHeap heap;
469 
470  if (target->map != source->map)
471  return default_dir;
472 
473  // These shouldn't change during the calculation, so store them once to avoid dereferencing.
474  mapstruct * cur_map = source->map; // Not constant to silence some warnings.
475  const uint16_t map_height = cur_map->height;
476  /*printf("monster_compute_path (%d, %d) => (%d, %d)\n", source->x, source->y, target->x, target->y);*/
477 
478  // Leave width like this because it is used just this once.
479  const int size = cur_map->width * map_height;
480 
481  // Determine the amount by which terrain is over or under valued by the monster.
482  /* terrain value is as follows:
483  * 0 - ignore terrain penalties
484  * 1 - undervalue terrain penalties by half
485  * 2 - correctly value terrain penalties
486  * 3 - overvalue terrain penalties by 50%
487  */
488  int terrain_value;
489  if (source->attack_movement & RUSH)
490  terrain_value = 0;
491  else if (source->stats.Int < 8) {
492  terrain_value = 0;
493  }
494  else if (source->stats.Int < 13) {
495  // If low Wis, then over-value terrain penalties.
496  // Otherwise, under-value terrain penalties.
497  if (source->stats.Wis < 13) {
498  terrain_value = 3;
499  }
500  else {
501  terrain_value = 1;
502  }
503  }
504  else {
505  terrain_value = 2;
506  }
507 
518  if (!source->more) // Skip multitile monsters, since this does not work right for them
519  {
520  dir = -1; // Set a sentinel. -1 = no escape, 0 = many ways out, [1, 8] = one way out in dir
521  for (i = 1; i <= 8; ++i)
522  {
523  x = source->x + freearr_x[i];
524  y = source->y + freearr_y[i];
525  if (OUT_OF_REAL_MAP(cur_map, x, y))
526  continue;
527  if (ob_blocked(source, cur_map, x, y))
528  continue;
529  // We have a way out. Make note of it
530  if (dir < 0)
531  dir = i;
532  // We have many ways out -- do the pathing part of the function
533  else
534  {
535  dir = 0;
536  break;
537  }
538  }
539  // If dir > 0, we have our direction to go, as it is our only choice.
540  if (dir > 0)
541  return dir;
542  // If dir < 0, then we have no way to go. Return default_dir.
543  if (dir < 0)
544  return default_dir;
545  }
546 
547  /* We are setting all the values manually anyway,
548  * so there's no reason to use calloc().
549  * malloc() is more efficient here for that reason.
550  */
551  distance = static_cast<path_data *>(malloc(size * sizeof(*distance)));
552  if (distance == NULL) {
554  }
555  /*
556  * To set to 65535 efficiently, though, I need to memset each byte to 255.
557  * each element is multiple bytes, and this will fill the non-distance values, too.
558  */
559  memset(distance, 255, sizeof(*distance) * size);
560 
561  // Set current to the starting point.
562  current = &distance[map_height * target->x + target->y];
563 
564  current->distance = 0;
565  current->x = target->x;
566  current->y = target->y;
567  current->heuristic_dist = 0;
568  current->movement_penalty = 0;
569 
570  // Initialize the minheap
571  minheap_init_static(&heap, (void **)heaparr, MAX_EXPLORE, path_measure_func);
572 
573  /* The first time through, current = 0 and max = 1.
574  * This will evaluate to true, so we might as well use a do-while loop.
575  */
576  do {
577  /* Fisher–Yates shuffle the directions, "inside-out" algorithm
578  * from http://en.wikipedia.org/wiki/Fisher-Yates_shuffle */
579  dirs[0] = 1;
580  for (i = 1; i < 8; ++i) {
581  x = RANDOM() % (i+1);
582  dirs[i] = dirs[x];
583  dirs[x] = i+1;
584  }
585 
586  for (i = 0; i < 8; ++i) {
587  uint16_t new_distance;
588 
589  /*
590  * dirs[i] is the direction we wish to check.
591  */
592  dir = absdir(default_dir+4+dirs[i]);
593  x = current->x+freearr_x[dir];
594  y = current->y+freearr_y[dir];
595 
596  if (x == source->x && y == source->y) {
597  // Randomly decide to bob/weave on some steps if not RUSH movement.
598  // When not in RUSH mode, 1/4 chance of bob/weaving
599  if (source->attack_movement != RUSH && (RANDOM() & 3) == 0) {
600  // We take the perspective of the source when determining our dodge/weave direction,
601  // incorporating the required dir+4 reversal immediately.
602  int newdir = absdir(dir+4+1-(RANDOM()&2)); // Bob/weave up to one space.
603  int newx = source->x+freearr_x[newdir],
604  newy = source->y+freearr_y[newdir];
605  // If we travel out of the map with this dodge, then we didn't try to path there.
606  // In such a case, we need to skip bob/weave and just go at the target.
607  if (!OUT_OF_REAL_MAP(source->map, newx, newy)) {
608  const path_data *newloc = &distance[map_height * newx + newy];
609  // If we checked the tile during pathing and it is not a wall and the movement penalty of the tile
610  // is not greater than the shortest-path's movement penalty, then go to that space.
611  if (newloc->distance != 65535 && newloc->distance != 1 &&
612  newloc->movement_penalty <= current->movement_penalty)
613  dir = newdir; // Commit to the bob/weave
614  else
615  dir = absdir(dir + 4);
616  }
617  else
618  dir = absdir(dir + 4);
619  }
620  // Otherwise, just follow the path we were given.
621  else
622  dir = absdir(dir + 4);
623  free(distance);
624  return dir;
625  }
626 
627  if (OUT_OF_REAL_MAP(cur_map, x, y))
628  continue;
629 
630  // Move these up, so we can reduce calls to ob_blocked with their info.
631  assert(map_height * x + y >= 0);
632  assert(map_height * x + y < size);
633 
634  // Set a pointer to the tile we are exploring.
635  explore = &distance[map_height * x + y];
636 
637  // Penalty-less spaces are handled by the inline if in the new_distance assignment.
638  // We can have move_penalty be zero because it assumes the penalty-less cost is already accounted for.
639  int16_t move_penalty = 0;
640  // Skip the penalty search if terrain value is zero. We will ignore any move penalty anyway.
641  if (terrain_value > 0) {
642  // Only calculate movement penalty if this tile does not have it yet.
643  if (explore->movement_penalty == -1) {
644  // Sum the move_slow_penalties on the map space.
645  object *tmp = GET_MAP_OB(cur_map, x, y);
647  if ((!source->move_type && tmp->move_slow&MOVE_WALK)
648  || ((source->move_type&tmp->move_slow) && (source->move_type&~tmp->move_slow&~tmp->move_block) == 0)) {
649  move_penalty += (int16_t)tmp->move_slow_penalty;
650  }
652  // And, make sure to store this for when we bump into this tile again
653  explore->movement_penalty = move_penalty;
654  }
655  else {
656  move_penalty = explore->movement_penalty;
657  }
658  }
659 
660  /* Mod 2 is equivalent to checking only the 1's bit (1 or 0), but & 1 is faster.
661  * Also, dir & 1 == 0 is true if we have a diagonal dir.
662  */
663  const int base_move_cost = ((dir & 1) == 0 ? 3 : 2);
664 
665  new_distance =
666  current->distance
667  // If terrain value is zero, we will ignore movement_penalties.
668  // If move_penalty is 0, then there were no penalties for moving onto this space.
669  + (move_penalty != 0 && terrain_value != 0 ? base_move_cost + base_move_cost * move_penalty * terrain_value / 2 : base_move_cost);
670 
671  // If already known blocked or arrivable in less distance, we skip
672  if (explore->distance <= new_distance)
673  continue;
674  // If we have a non-default value here, we will have lready done ob_blocked on it.
675  // So, only call ob_blocked if we are staring at 65535.
676  // If we are not looking at an untested space, then we will skip this block and avoid ob_blocked
677  if (explore->distance == 65535 && ob_blocked(source, cur_map, x, y))
678  {
679  // Mark as something we can't otherwise get -- the goal is to cache what spaces are blocked.
680  // At least, this call to monster_compute_path will remember this spot is blocked.
681  // This should cut our calls to ob_blocked some.
682  explore->distance = 1;
683  // The value of 1 also allows for walls to be considered already checked, but since we do not add to the
684  // explore array, this makes them hit the condition above if they are checked again without going through walls.
685  continue;
686  }
687 
688  /*LOG(llevDebug, "check %d, %d dist = %d, nd = %d\n", x, y, distance[source->map->height*x+y], new_distance);*/
689 
690  // Only set x and y when we insert into the minheap.
691  explore->x = x;
692  explore->y = y;
693  explore->distance = new_distance;
694  explore->heuristic_dist = estimate_distance(x, y, source->x, source->y); // Add a heuristic to make this A*.
695  /* printf("explore[%d] => (%d, %d) %u\n", max, x, y, new_distance);*/
696 
697  // TODO: If the space has already been evaluated, we'd really want to do an in-place update, not an insert.
698 
699  // If the heap is full when we try to insert, then we have exhausted exploration space.
700  if (minheap_insert(&heap, explore) != 0) {
701  free(distance);
702  return default_dir;
703  }
704  }
705  current = static_cast<path_data *>(minheap_remove(&heap));
706  } while (current != NULL);
707 
708  /*LOG(llevDebug, "no path\n");*/
709  free(distance);
710  return default_dir;
711 }
712 
719 void monster_do_living(object *op) {
720  assert(op);
721  assert(QUERY_FLAG(op, FLAG_MONSTER));
722 
723  /* generate hp, if applicable */
724  if (op->stats.Con > 0 && op->stats.hp < op->stats.maxhp) {
725  /* last heal is in funny units. Dividing by speed puts
726  * the regeneration rate on a basis of time instead of
727  * #moves the monster makes. The scaling by 8 is
728  * to capture 8th's of a hp fraction regens
729  *
730  * Cast to int32_t before comparing to maxhp since otherwise an (int16_t)
731  * overflow might produce monsters with negative hp.
732  */
733 
734  op->last_heal += (int)((float)(8*op->stats.Con)/FABS(op->speed));
735  op->stats.hp = MIN((int32_t)op->stats.hp+op->last_heal/32, op->stats.maxhp); /* causes Con/4 hp/tick */
736  op->last_heal %= 32;
737 
738  /* So if the monster has gained enough HP that they are no longer afraid */
740  && op->stats.hp >= (int16_t)((int32_t)op->run_away * op->stats.maxhp / 100))
742  /*
743  * This should already be covered by the MIN() check above.
744 
745  if (op->stats.hp > op->stats.maxhp)
746  op->stats.hp = op->stats.maxhp;
747  */
748  }
749 
750  /* generate sp, if applicable */
751  if (op->stats.Pow > 0 && op->stats.sp < op->stats.maxsp) {
752  /* last_sp is in funny units. Dividing by speed puts
753  * the regeneration rate on a basis of time instead of
754  * #moves the monster makes. The scaling by 8 is
755  * to capture 8th's of a sp fraction regens
756  *
757  * Cast to int32_t before comparing to maxhp since otherwise an (int16_t)
758  * overflow might produce monsters with negative sp.
759  */
760 
761  op->last_sp += (int)((float)(8*op->stats.Pow)/FABS(op->speed));
762  op->stats.sp = MIN(op->stats.sp+op->last_sp/128, op->stats.maxsp); /* causes Pow/16 sp/tick */
763  op->last_sp %= 128;
764  }
765 
766  /* this should probably get modified by many more values.
767  * (eg, creatures resistance to fear, level, etc. )
768  */
769  if (QUERY_FLAG(op, FLAG_SCARED) && !(RANDOM()%20)) {
770  CLEAR_FLAG(op, FLAG_SCARED); /* Time to regain some "guts"... */
771  }
772 }
773 
782 static int monster_move_no_enemy(object *op) {
783  assert(QUERY_FLAG(op, FLAG_MONSTER));
784 
786  object_remove(op);
788  return 1;
789  }
790 
791  /* Probably really a bug for a creature to have both
792  * stand still and a movement type set.
793  */
794  if (!QUERY_FLAG(op, FLAG_STAND_STILL)) {
795  if (op->attack_movement&HI4) {
796  switch (op->attack_movement&HI4) {
797  case PETMOVE:
798  pets_move(op);
799  break;
800 
801  case CIRCLE1:
803  break;
804 
805  case CIRCLE2:
807  break;
808 
809  case PACEV:
811  break;
812 
813  case PACEH:
815  break;
816 
817  case PACEV2:
819  break;
820 
821  case PACEH2:
823  break;
824 
825  case RANDO:
827  break;
828 
829  case RANDO2:
831  break;
832  }
833  return 0;
834  }
835 
838  } /* stand still */
839 
840  return 0;
841 }
842 
854 int monster_move(object *op) {
855  int dir, diff;
856  object *owner, *enemy, *part;
857  rv_vector rv;
858 
859  /* Monsters not on maps don't do anything. These monsters are things
860  * Like royal guards in city dwellers inventories.
861  */
862  if (!op->map)
863  return 0;
864 
865  if (QUERY_FLAG(op, FLAG_NO_ATTACK)) { /* we never ever attack */
866  object_set_enemy(op, NULL);
867  enemy = NULL;
868  } else {
869  enemy = monster_find_enemy(op, &rv);
870  if (enemy != NULL) {
871  /* we have an enemy, just tell him we want him dead */
872  enemy->attacked_by = op; /* our ptr */
873  enemy->attacked_by_count = op->count; /* our tag */
874  }
875  }
876 
878 
879  if (QUERY_FLAG(op, FLAG_SLEEP)
881  || (op->map->darkness > 0 && !QUERY_FLAG(op, FLAG_SEE_IN_DARK) && !QUERY_FLAG(op, FLAG_SEE_INVISIBLE))) {
882  if (!monster_check_wakeup(op, enemy, &rv))
883  return 0;
884  }
885 
886  /* check if monster pops out of hidden spot */
887  if (op->hide)
889 
890  if (op->pick_up)
892 
893  if (op->will_apply)
894  monster_apply_below(op); /* Check for items to apply below */
895 
896  // Can happen due to monster_apply_below().
897  if (QUERY_FLAG(op, FLAG_REMOVED)) {
898  return 1;
899  }
900 
901  /* If we don't have an enemy, do special movement or the like */
902  if (!enemy) {
903  return monster_move_no_enemy(op);
904  } /* no enemy */
905 
906  /* We have an enemy. Block immediately below is for pets */
907  if ((op->attack_movement&HI4) == PETMOVE) {
908  owner = object_get_owner(op);
909  if (owner != NULL && !on_same_map(op, owner)) {
910  pets_follow_owner(op, owner);
911  /* If the pet was unable to follow the owner, free it */
912  if (QUERY_FLAG(op, FLAG_REMOVED) && FABS(op->speed) > MIN_ACTIVE_SPEED) {
915  return 1;
916  }
917  return 0;
918  }
919  }
920 
921  /* doppleganger code to change monster facing to that of the nearest
922  * player. Hmm. The code is here, but no monster in the current
923  * arch set uses it.
924  */
925  if (op->race != NULL && strcmp(op->race, "doppleganger") == 0) {
926  op->face = enemy->face;
927  if (op->name)
928  free_string(op->name);
929  add_refcount(op->name = enemy->name);
930  }
931 
932  /* Calculate range information for closest body part - this
933  * is used for the 'skill' code, which isn't that smart when
934  * it comes to figuring it out - otherwise, giants throw boulders
935  * into themselves.
936  */
937  if (!get_rangevector(op, enemy, &rv, 0))
938  return 0;
939  if (op->direction != rv.direction) {
940  op->direction = rv.direction;
941  op->facing = op->direction;
942  if (op->animation)
943  animate_object(op, op->direction);
944  }
945 
946  // We are looking at movement -- if monster was paralyzed, they aren't anymore
947  if (QUERY_FLAG(op, FLAG_PARALYZED)) {
949  }
950 
951  /* Move the check for scared up here - if the monster was scared,
952  * we were not doing any of the logic below, so might as well save
953  * a few cpu cycles.
954  */
955  if (!QUERY_FLAG(op, FLAG_SCARED)) {
956  dir = rv.direction;
957 
958  /* Was two if statements assigning to the same variable
959  * We can get the same effect by reversing the order and making an else-if
960  */
962  dir = get_randomized_dir(dir);
963  else if (QUERY_FLAG(op, FLAG_RUN_AWAY))
964  dir = absdir(dir+4);
965 
966  if (QUERY_FLAG(op, FLAG_CAST_SPELL) && !(RANDOM()%3)) {
967  if (monster_cast_spell(op, rv.part, enemy, dir))
968  return 0;
969  }
970 
971  if (QUERY_FLAG(op, FLAG_READY_SCROLL) && !(RANDOM()%3)) {
972  if (monster_use_scroll(op, rv.part, enemy, dir))
973  return 0;
974  }
975 
976  if (QUERY_FLAG(op, FLAG_READY_RANGE) && !(RANDOM()%3)) {
977  if (monster_use_range(op, rv.part, enemy, dir))
978  return 0;
979  }
980  if (QUERY_FLAG(op, FLAG_READY_SKILL) && !(RANDOM()%3)) {
981  if (monster_use_skill(op, rv.part, enemy, rv.direction))
982  return 0;
983  }
984  if (QUERY_FLAG(op, FLAG_READY_BOW) && !(RANDOM()%2)) {
985  if (monster_use_bow(op, rv.part, enemy, dir))
986  return 0;
987  }
988  } /* If not scared */
989 
990 
991  /* code below is for when we didn't use a range attack or a skill, so
992  * either move or hit with hth attack. */
993 
994  part = rv.part;
995  dir = rv.direction;
996 
997  /* This first clause used to happen after the other two, but would trample dir.
998  * Moved to before them as another check to slightly reduce calls to monster_compute_path
999  */
1000  if (QUERY_FLAG(op, FLAG_CONFUSED))
1001  dir = get_randomized_dir(dir);
1003  dir = absdir(dir+4);
1004  else if (!monster_can_hit(part, enemy, &rv)) {
1005  dir = monster_compute_path(op, enemy, -1);
1006  if (dir == -1) {
1007  // Can't reach enemy, so remove it, attempt to move in its last direction so not stay still
1008  LOG(llevMonster, "monster %s (%d, %d on %s) can't reach enemy %s (%d, %d on %s)\n",
1009  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)");
1010  object_set_enemy(op, NULL);
1011  dir = rv.direction;
1012  }
1013  }
1014 
1015  if ((op->attack_movement&LO4) && !QUERY_FLAG(op, FLAG_SCARED)) {
1016  switch (op->attack_movement&LO4) {
1017  case DISTATT:
1018  dir = monster_dist_att(dir, enemy, part, &rv);
1019  break;
1020 
1021  case RUNATT:
1022  dir = monster_run_att(dir, op, enemy, part, &rv);
1023  break;
1024 
1025  case HITRUN:
1026  dir = monster_hitrun_att(dir, op);
1027  break;
1028 
1029  case WAITATT:
1030  dir = monster_wait_att(dir, op, enemy, part, &rv);
1031  break;
1032 
1033  case RUSH: /* default - monster normally moves towards player */
1034  case ALLRUN:
1035  break;
1036 
1037  case DISTHIT:
1038  dir = monster_disthit_att(dir, op, enemy, part, &rv);
1039  break;
1040 
1041  case WAIT2:
1042  dir = monster_wait_att2(dir, &rv);
1043  break;
1044 
1045  default:
1046  LOG(llevDebug, "Illegal low mon-move: %d\n", op->attack_movement&LO4);
1047  }
1048  }
1049 
1050  if (!dir)
1051  return 0;
1052 
1053  if (!QUERY_FLAG(op, FLAG_STAND_STILL)) {
1054  if (move_object(op, dir)) /* Can the monster move directly toward player? */
1055  return 0;
1056 
1057  if (QUERY_FLAG(op, FLAG_SCARED)
1058  || !monster_can_hit(part, enemy, &rv)
1059  || QUERY_FLAG(op, FLAG_RUN_AWAY)) {
1060  /* Try move around corners if !close */
1061  int maxdiff = (QUERY_FLAG(op, FLAG_ONLY_ATTACK) || RANDOM()&1) ? 1 : 2;
1062  for (diff = 1; diff <= maxdiff; diff++) {
1063  /* try different detours */
1064  int m = 1-(RANDOM()&2); /* Try left or right first? */
1065  if (move_object(op, absdir(dir+diff*m))
1066  || move_object(op, absdir(dir-diff*m)))
1067  return 0;
1068  }
1069  }
1070  } /* if monster is not standing still */
1071 
1072  /*
1073  * Eneq(@csd.uu.se): Patch to make RUN_AWAY or SCARED monsters move a random
1074  * direction if they can't move away.
1075  */
1079  return 0;
1080 
1081  /*
1082  * Try giving the monster a new enemy - the player that is closest
1083  * to it. In this way, it won't just keep trying to get to a target
1084  * that is inaccessible.
1085  * This could be more clever - it should go through a list of several
1086  * enemies, as it is now, you could perhaps get situations where there
1087  * are two players flanking the monster at close distance, but which
1088  * the monster can't get to, and a third one at a far distance that
1089  * the monster could get to - as it is, the monster won't look at that
1090  * third one.
1091  */
1092  if (!QUERY_FLAG(op, FLAG_FRIENDLY) && enemy == op->enemy) {
1093  object *nearest_player = get_nearest_player(op);
1094 
1095  if (nearest_player && nearest_player != enemy && !monster_can_hit(part, enemy, &rv)) {
1096  object_set_enemy(op, NULL);
1097  enemy = nearest_player;
1098  }
1099  }
1100 
1101  if (!QUERY_FLAG(op, FLAG_SCARED) && monster_can_hit(part, enemy, &rv)) {
1102  /* The adjustement to wc that was here before looked totally bogus -
1103  * since wc can in fact get negative, that would mean by adding
1104  * the current wc, the creature gets better? Instead, just
1105  * add a fixed amount - nasty creatures that are runny away should
1106  * still be pretty nasty.
1107  */
1108  if (QUERY_FLAG(op, FLAG_RUN_AWAY)) {
1109  part->stats.wc += 10;
1110  skill_attack(enemy, part, 0, NULL, NULL);
1111  part->stats.wc -= 10;
1112  } else
1113  skill_attack(enemy, part, 0, NULL, NULL);
1114  } /* if monster is in attack range */
1115 
1116  if (QUERY_FLAG(part, FLAG_FREED)) /* Might be freed by ghost-attack or hit-back */
1117  return 1;
1118 
1119  if (QUERY_FLAG(op, FLAG_ONLY_ATTACK)) {
1120  object_remove(op);
1122  return 1;
1123  }
1124  return 0;
1125 }
1126 
1141 static int monster_can_hit(object *ob1, object *ob2, rv_vector *rv) {
1142  object *more;
1143  rv_vector rv1;
1144 
1145  if (QUERY_FLAG(ob1, FLAG_CONFUSED) && !(RANDOM()%3))
1146  return 0;
1147 
1148  if (abs(rv->distance_x) < 2 && abs(rv->distance_y) < 2)
1149  return 1;
1150 
1151  /* check all the parts of ob2 - just because we can't get to
1152  * its head doesn't mean we don't want to pound its feet
1153  */
1154  for (more = ob2->more; more != NULL; more = more->more) {
1155  if (get_rangevector(ob1, more, &rv1, 0)
1156  && abs(rv1.distance_x) < 2 && abs(rv1.distance_y) < 2)
1157  return 1;
1158  }
1159  return 0;
1160 }
1161 
1184 static int monster_should_cast_spell(object *spell_ob) {
1185  /* The caller is responsible for making sure that *spell_ob is defined. */
1186  assert(spell_ob != NULL);
1187 
1188  switch (spell_ob->subtype) {
1189  case SP_BOLT:
1190  case SP_BULLET:
1191  case SP_EXPLOSION:
1192  case SP_CONE:
1193  case SP_BOMB:
1194  case SP_SMITE:
1195  case SP_MAGIC_MISSILE:
1196  case SP_SUMMON_GOLEM:
1197  case SP_MAGIC_WALL:
1198  case SP_SUMMON_MONSTER:
1199  case SP_MOVING_BALL:
1200  case SP_SWARM:
1201  case SP_INVISIBLE:
1202  case SP_AURA:
1203  return 1;
1204  }
1205 
1206  return 0;
1207 }
1208 
1210 #define MAX_KNOWN_SPELLS 20
1211 
1227 static object *monster_choose_random_spell(object *monster) {
1228  object *altern[MAX_KNOWN_SPELLS];
1229  int i = 0;
1230 
1231  FOR_INV_PREPARE(monster, tmp)
1232  if (tmp->type == SPELLBOOK || tmp->type == SPELL) {
1233  /* Check and see if it's actually a useful spell.
1234  * If its a spellbook, the spell is actually the inventory item.
1235  * if it is a spell, then it is just the object itself.
1236  */
1237  if (monster_should_cast_spell(tmp->type == SPELLBOOK ? tmp->inv : tmp)) {
1238  altern[i++] = tmp;
1239  if (i == MAX_KNOWN_SPELLS)
1240  break;
1241  }
1242  }
1243  FOR_INV_FINISH();
1244  if (!i)
1245  return NULL;
1246  return altern[RANDOM()%i];
1247 }
1248 
1265 static int monster_cast_spell(object *head, object *part, object *pl, int dir) {
1266  object *spell_item;
1267  object *owner;
1268  rv_vector rv1;
1269 
1270  /* If you want monsters to cast spells over friends, this spell should
1271  * be removed. It probably should be in most cases, since monsters still
1272  * don't care about residual effects (ie, casting a cone which may have a
1273  * clear path to the player, the side aspects of the code will still hit
1274  * other monsters)
1275  */
1276  dir = path_to_player(part, pl, 0);
1277  if (dir == 0)
1278  return 0;
1279 
1280  if (QUERY_FLAG(head, FLAG_FRIENDLY)) {
1281  owner = object_get_owner(head);
1282  if (owner != NULL) {
1283  if (get_rangevector(head, owner, &rv1, 0x1)
1284  && dirdiff(dir, rv1.direction) < 2) {
1285  return 0; /* Might hit owner with spell */
1286  }
1287  }
1288  }
1289 
1290  if (QUERY_FLAG(head, FLAG_CONFUSED))
1291  dir = get_randomized_dir(dir);
1292 
1293  /* If the monster hasn't already chosen a spell, choose one
1294  * I'm not sure if it really make sense to pre-select spells (events
1295  * could be different by the time the monster goes again).
1296  */
1297  if (head->spellitem == NULL) {
1298  spell_item = monster_choose_random_spell(head);
1299  if (spell_item == NULL) {
1300  LOG(llevMonster, "Turned off spells in %s\n", head->name);
1301  CLEAR_FLAG(head, FLAG_CAST_SPELL); /* Will be turned on when picking up book */
1302  return 0;
1303  }
1304  if (spell_item->type == SPELLBOOK) {
1305  if (!spell_item->inv) {
1306  LOG(llevError, "spellbook %s does not contain a spell?\n", spell_item->name);
1307  return 0;
1308  }
1309  spell_item = spell_item->inv;
1310  }
1311  } else
1312  spell_item = head->spellitem;
1313 
1314  if (!spell_item)
1315  return 0;
1316 
1317  /* Best guess this is a defensive/healing spell */
1318  if (spell_item->range <= 1 || spell_item->stats.dam < 0)
1319  dir = 0;
1320 
1321  /* Monster doesn't have enough spell-points */
1322  /* As of 2023, monsters do not possess grace points, and so will use sp for prayers too. */
1323  if (head->stats.sp < SP_level_spellpoint_cost(head, spell_item, SPELL_MANA))
1324  return 0;
1325 
1326  if (head->stats.sp < SP_level_spellpoint_cost(head, spell_item, SPELL_GRACE))
1327  return 0;
1328 
1329  head->stats.sp -= SP_level_spellpoint_cost(head, spell_item, SPELL_MANA);
1330  head->stats.sp -= SP_level_spellpoint_cost(head, spell_item, SPELL_GRACE);
1331 
1332  /* set this to null, so next time monster will choose something different */
1333  head->spellitem = NULL;
1334 
1335  return cast_spell(part, part, dir, spell_item, NULL);
1336 }
1337 
1352 static int monster_use_scroll(object *head, object *part, object *pl, int dir) {
1353  object *scroll;
1354  object *owner;
1355  rv_vector rv1;
1356 
1357  /* If you want monsters to cast spells over friends, this spell should
1358  * be removed. It probably should be in most cases, since monsters still
1359  * don't care about residual effects (ie, casting a cone which may have a
1360  * clear path to the player, the side aspects of the code will still hit
1361  * other monsters)
1362  */
1363  dir = path_to_player(part, pl, 0);
1364  if (dir == 0)
1365  return 0;
1366 
1367  if (QUERY_FLAG(head, FLAG_FRIENDLY)) {
1368  owner = object_get_owner(head);
1369  if (owner != NULL) {
1370  if (get_rangevector(head, owner, &rv1, 0x1)
1371  && dirdiff(dir, rv1.direction) < 2) {
1372  return 0; /* Might hit owner with spell */
1373  }
1374  }
1375  }
1376 
1377  if (QUERY_FLAG(head, FLAG_CONFUSED))
1378  dir = get_randomized_dir(dir);
1379 
1380  scroll = NULL;
1381  FOR_INV_PREPARE(head, tmp)
1382  if (tmp->type == SCROLL && monster_should_cast_spell(tmp->inv)) {
1383  scroll = tmp;
1384  break;
1385  }
1386  FOR_INV_FINISH();
1387 
1388  /* Used up all his scrolls, so nothing do to */
1389  if (!scroll) {
1391  return 0;
1392  }
1393 
1394  /* Spell should be cast on caster (ie, heal, strength) */
1395  if (scroll->inv->range == 0)
1396  dir = 0;
1397 
1398  /* Face the direction that we want to cast. */
1399  head->direction = dir;
1400  head->facing = head->direction;
1401  if (head->animation)
1402  animate_object(head, head->direction);
1403 
1404  apply_manual(part, scroll, 0);
1405  return 1;
1406 }
1407 
1436 static int monster_use_skill(object *head, object *part, object *pl, int dir) {
1437  object *owner;
1438  int found;
1439 
1440  dir = path_to_player(part, pl, 0);
1441  if (dir == 0)
1442  return 0;
1443 
1444  if (QUERY_FLAG(head, FLAG_FRIENDLY)) {
1445  owner = object_get_owner(head);
1446  if (owner != NULL) {
1447  rv_vector rv;
1448 
1449  if (get_rangevector(head, owner, &rv, 0) && dirdiff(dir, rv.direction) < 1)
1450  return 0; /* Might hit owner with skill -thrown rocks for example ?*/
1451  }
1452  }
1453  if (QUERY_FLAG(head, FLAG_CONFUSED))
1454  dir = get_randomized_dir(dir);
1455 
1456  /* skill selection - monster will use the next unused skill.
1457  * well...the following scenario will allow the monster to
1458  * toggle between 2 skills. One day it would be nice to make
1459  * more skills available to monsters.
1460  */
1461  found = 0;
1462  FOR_INV_PREPARE(head, skill)
1463  if (skill->type == SKILL && skill != head->chosen_skill) {
1464  head->chosen_skill = skill;
1465  found = 1;
1466  break;
1467  }
1468  FOR_INV_FINISH();
1469 
1470  if (!found && !head->chosen_skill) {
1471  LOG(llevDebug, "Error: Monster %s (%d) has FLAG_READY_SKILL without skill.\n", head->name, head->count);
1473  return 0;
1474  }
1475  /* use skill */
1476  return do_skill(head, part, head->chosen_skill, dir, NULL);
1477 }
1478 
1493 static int monster_use_range(object *head, object *part, object *pl, int dir) {
1494  object *owner;
1495  int at_least_one = 0;
1496 
1497  dir = path_to_player(part, pl, 0);
1498  if (dir == 0)
1499  return 0;
1500 
1501  if (QUERY_FLAG(head, FLAG_FRIENDLY)) {
1502  owner = object_get_owner(head);
1503  if (owner != NULL) {
1504  rv_vector rv;
1505 
1506  if (get_rangevector(head, owner, &rv, 0) && dirdiff(dir, rv.direction) < 2)
1507  return 0; /* Might hit owner with spell */
1508  }
1509  }
1510  if (QUERY_FLAG(head, FLAG_CONFUSED))
1511  dir = get_randomized_dir(dir);
1512 
1513  FOR_INV_PREPARE(head, wand) {
1514  if (wand->type == WAND) {
1515  /* Found a wand, let's see if it has charges left */
1516  at_least_one = 1;
1517  if (wand->stats.food <= 0)
1518  continue;
1519 
1520  cast_spell(head, wand, dir, wand->inv, NULL);
1521  drain_wand_charge(wand);
1522 
1523  /* Success */
1524  return 1;
1525  }
1526 
1527  if (wand->type == ROD && wand->inv) {
1528  /* Found rod/horn, let's use it if possible */
1529  at_least_one = 1;
1530  if (wand->stats.hp < MAX(wand->inv->stats.sp, wand->inv->stats.grace))
1531  continue;
1532 
1533  /* drain charge before casting spell - can be a case where the
1534  * spell destroys the monster, and rod, so if done after, results
1535  * in crash.
1536  */
1537  drain_rod_charge(wand);
1538  cast_spell(head, wand, dir, wand->inv, NULL);
1539 
1540  /* Success */
1541  return 1;
1542  }
1543  } FOR_INV_FINISH();
1544 
1545  if (at_least_one)
1546  return 0;
1547 
1548  LOG(llevError, "Error: Monster %s (%d) HAS_READY_RANG() without wand/horn/rod.\n", head->name, head->count);
1550  return 0;
1551 }
1552 
1569 static int monster_use_bow(object *head, object *part, object *pl, int dir) {
1570  object *owner;
1571  rv_vector rv;
1572  int16_t x, y;
1573  mapstruct *map;
1574 
1575  if (!get_rangevector(part, pl, &rv, 1))
1576  return 0;
1577  if (rv.distance > 100)
1578  /* Too far */
1579  return 0;
1580  if (rv.distance_x != 0 && rv.distance_y != 0 && abs(rv.distance_x) != abs(rv.distance_y))
1581  /* Player must be on same horizontal, vertical or diagonal line. */
1582  return 0;
1583  dir = rv.direction;
1584 
1585  if (QUERY_FLAG(head, FLAG_FRIENDLY))
1586  owner = object_get_owner(head);
1587  else
1588  owner = NULL;
1589 
1590  /* The monster can possibly fire, let's see if the path is ok for an arrow. */
1591  x = part->x;
1592  y = part->y;
1593  map = part->map;
1594  while (x != pl->x || y != pl->y || map != pl->map) {
1595  x += freearr_x[dir];
1596  y += freearr_y[dir];
1597  map = get_map_from_coord(map, &x, &y);
1598  if (!map) {
1599  LOG(llevError, "monster_use_bow: no map but still path exists??\n");
1600  return 0;
1601  }
1603  return 0;
1604  if (owner && owner->x == x && owner->y == y && owner->map == map)
1605  /* Don't hit owner! */
1606  return 0;
1607  }
1608 
1609  /* Finally, path is clear, can fire. */
1610 
1611  if (QUERY_FLAG(head, FLAG_CONFUSED))
1612  dir = get_randomized_dir(dir);
1613 
1614  /* in server/player.c */
1615  return fire_bow(head, NULL, dir, 0, part->x, part->y);
1616 }
1617 
1626 static int monster_get_weapon_quality(const object *item) {
1627  int val;
1628  int i;
1629 
1630  val = item->stats.dam;
1631  val += item->magic*3;
1632  /* Monsters don't really get benefits from things like regen rates
1633  * from items. But the bonus for their stats are very important.
1634  */
1635  for (i = 0; i < NUM_STATS; i++)
1636  val += get_attr_value(&item->stats, i)*2;
1637  return val;
1638 }
1639 
1652 static int monster_check_good_weapon(object *who, object *item) {
1653  object *other_weap;
1654  int val;
1655 
1656  other_weap = object_find_by_type_applied(who, item->type);
1657  if (other_weap == NULL) /* No other weapons */
1658  return 1;
1659 
1660  /* Rather than go through and apply the new one, and see if it is
1661  * better, just do some simple checks
1662  * Put some multipliers for things that hvae several effects,
1663  * eg, magic affects both damage and wc, so it has more weight
1664  */
1665 
1667  return val > 0;
1668 }
1669 
1678 static int monster_get_armour_quality(const object *item) {
1679  int val;
1680 
1681  val = item->stats.ac;
1682  val += item->resist[ATNR_PHYSICAL]/5;
1683  val += item->magic*3;
1684  return val;
1685 }
1686 
1699 static int monster_check_good_armour(object *who, object *item) {
1700  object *other_armour;
1701  int val, i;
1702 
1703  other_armour = object_find_by_type_applied(who, item->type);
1704  if (other_armour == NULL) /* No other armour, use the new */
1705  return 1;
1706 
1708 
1709  /* for the other protections, do weigh them very much in the equation -
1710  * it is the armor protection which is most important, because there is
1711  * no good way to know what the player may attack the monster with.
1712  * So if the new item has better protection than the old, give that higher
1713  * value. If the reverse, then decrease the value of this item some.
1714  */
1715  for (i = 1; i < NROFATTACKS; i++) {
1716  if (item->resist[i] > other_armour->resist[i])
1717  val++;
1718  else if (item->resist[i] < other_armour->resist[i])
1719  val--;
1720  }
1721 
1722  /* Very few armours have stats, so not much need to worry about those. */
1723 
1724  return val > 0;
1725 }
1726 
1734 static void monster_check_apply(object *mon, object *item) {
1735  int flag = 0;
1736 
1737  if (item->type == SPELLBOOK
1738  && mon->arch != NULL
1739  && (QUERY_FLAG(&mon->arch->clone, FLAG_CAST_SPELL))) {
1741  return;
1742  }
1743 
1744  /* If for some reason, this item is already applied, no more work to do */
1746  return;
1747 
1748  /* Might be better not to do this - if the monster can fire a bow,
1749  * it is possible in his wanderings, he will find one to use. In
1750  * which case, it would be nice to have ammo for it.
1751  */
1752  if (QUERY_FLAG(mon, FLAG_USE_BOW) && item->type == ARROW) {
1753  /* Check for the right kind of bow */
1754  object *bow;
1755 
1756  bow = object_find_by_type_and_race(mon, BOW, item->race);
1757  if (bow != NULL) {
1759  LOG(llevMonster, "Found correct bow for arrows.\n");
1760  return; /* nothing more to do for arrows */
1761  }
1762  }
1763 
1764  if (item->type == TREASURE && mon->will_apply&WILL_APPLY_TREASURE)
1765  flag = 1;
1766  /* Eating food gets hp back */
1767  else if (item->type == FOOD && mon->will_apply&WILL_APPLY_FOOD)
1768  flag = 1;
1769  else if (item->type == SCROLL && QUERY_FLAG(mon, FLAG_USE_SCROLL)) {
1770  if (!item->inv)
1771  LOG(llevDebug, "Monster %d having scroll %d with empty inventory!\n", mon->count, item->count);
1772  else if (monster_should_cast_spell(item->inv))
1774  /* Don't use it right now */
1775  return;
1776  } else if (item->type == WEAPON)
1778  else if (IS_ARMOR(item) || IS_SHIELD(item))
1780  /* Should do something more, like make sure this is a better item */
1781  else if (item->type == RING)
1782  flag = 1;
1783  else if (item->type == WAND || item->type == ROD) {
1784  /* We never really 'ready' the wand/rod/horn, because that would mean the
1785  * weapon would get undone.
1786  */
1790  }
1791  return;
1792  } else if (item->type == BOW) {
1793  /* We never really 'ready' the bow, because that would mean the
1794  * weapon would get undone.
1795  */
1798  return;
1799  } else if (item->type == SKILL) {
1800  /*
1801  * skills are specials: monsters must have the 'FLAG_READY_SKILL' flag set,
1802  * else they can't use the skill...
1803  * Skills also don't need to get applied, so return now.
1804  */
1806  return;
1807  }
1808 
1809  /* if we don't match one of the above types, return now.
1810  * apply_can_apply_object() will say that we can apply things like flesh,
1811  * bolts, and whatever else, because it only checks against the
1812  * body_info locations.
1813  */
1814  if (!flag)
1815  return;
1816 
1817  /* Check to see if the monster can use this item. If not, no need
1818  * to do further processing. Note that apply_can_apply_object() already checks
1819  * for the CAN_USE flags.
1820  */
1822  return;
1823 
1824  /* should only be applying this item, not unapplying it.
1825  * also, ignore status of curse so they can take off old armour.
1826  * monsters have some advantages after all.
1827  */
1829  return;
1830 }
1831 
1851 static void monster_check_pickup(object *monster) {
1852  object *part;
1853 
1854  for (part = monster; part != NULL; part = part->more)
1855  FOR_BELOW_PREPARE(part, tmp) {
1856  /* Don't try to pick items that are in the process of being thrown.
1857  * It is fairly likely that an ally threw it past monster to hit player.
1858  * IDEA: Maybe have a dex save to catch player-thrown projectiles?
1859  *
1860  * Neila Hawkins 2020-09-07
1861  */
1862  if (tmp->type != THROWN_OBJ && monster_can_pick(monster, tmp)) {
1863  uint32_t nrof;
1864 
1865  if (tmp->weight > 0) {
1866  int32_t weight_limit;
1867 
1868  weight_limit = get_weight_limit(monster->stats.Str);
1869  if (weight_limit >= monster->weight-monster->carrying)
1870  nrof = (weight_limit-monster->weight-monster->carrying)/tmp->weight;
1871  else
1872  nrof = 0;
1873  } else
1874  nrof = MAX(1, tmp->nrof);
1875  if (nrof >= 1) {
1876  object *tmp2;
1877 
1878  tmp2 = object_split(tmp, MIN(nrof, MAX(1, tmp->nrof)), NULL, 0);
1879  tmp2 = object_insert_in_ob(tmp2, monster);
1880  (void)monster_check_apply(monster, tmp2);
1881  }
1882  }
1883  } FOR_BELOW_FINISH();
1884 }
1885 
1895 static int monster_can_pick(object *monster, object *item) {
1896  int flag = 0;
1897  int i;
1898 
1899  if (!object_can_pick(monster, item))
1900  return 0;
1901 
1902  if (QUERY_FLAG(item, FLAG_UNPAID))
1903  return 0;
1904 
1905  if (monster->pick_up&64) /* All */
1906  flag = 1;
1907 
1908  else {
1909  if (IS_WEAPON(item))
1910  flag = (monster->pick_up&8) || QUERY_FLAG(monster, FLAG_USE_WEAPON);
1911  else if (IS_ARMOR(item))
1912  flag = (monster->pick_up&16) || QUERY_FLAG(monster, FLAG_USE_ARMOUR);
1913  else if (IS_SHIELD(item))
1914  flag = (monster->pick_up&16) || QUERY_FLAG(monster, FLAG_USE_SHIELD);
1915  else switch (item->type) {
1916  case MONEY:
1917  case GEM:
1918  flag = monster->pick_up&2;
1919  break;
1920 
1921  case FOOD:
1922  flag = monster->pick_up&4;
1923  break;
1924 
1925  case SKILL:
1926  flag = QUERY_FLAG(monster, FLAG_CAN_USE_SKILL);
1927  break;
1928 
1929  case RING:
1930  flag = QUERY_FLAG(monster, FLAG_USE_RING);
1931  break;
1932 
1933  case WAND:
1934  case ROD:
1935  flag = QUERY_FLAG(monster, FLAG_USE_RANGE);
1936  break;
1937 
1938  case SPELLBOOK:
1939  flag = (monster->arch != NULL && QUERY_FLAG(&monster->arch->clone, FLAG_CAST_SPELL));
1940  break;
1941 
1942  case SCROLL:
1943  flag = QUERY_FLAG(monster, FLAG_USE_SCROLL);
1944  break;
1945 
1946  case BOW:
1947  case ARROW:
1948  flag = QUERY_FLAG(monster, FLAG_USE_BOW);
1949  break;
1950  }
1951  if (!flag && QUERY_FLAG(item, FLAG_IS_THROWN) && object_find_by_type_subtype(monster, SKILL, SK_THROWING) != NULL)
1952  flag = (monster->pick_up&8) || QUERY_FLAG(monster, FLAG_USE_WEAPON);
1953  /* Simplistic check - if the monster has a location to equip it, he will
1954  * pick it up. Note that this doesn't handle cases where an item may
1955  * use several locations.
1956  */
1957  for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
1958  if (monster->body_info[i] && item->body_info[i]) {
1959  flag = 1;
1960  break;
1961  }
1962  }
1963  }
1964 
1965  if (((!(monster->pick_up&32)) && flag) || ((monster->pick_up&32) && (!flag)))
1966  return 1;
1967  return 0;
1968 }
1969 
1976 static void monster_apply_below(object *monster) {
1977  FOR_BELOW_PREPARE(monster, tmp) {
1978  switch (tmp->type) {
1979  case CF_HANDLE:
1980  case TRIGGER:
1981  if (monster->will_apply&WILL_APPLY_HANDLE)
1982  apply_manual(monster, tmp, 0);
1983  break;
1984 
1985  case TREASURE:
1986  if (monster->will_apply&WILL_APPLY_TREASURE)
1987  apply_manual(monster, tmp, 0);
1988  break;
1989  }
1991  break;
1992  } FOR_BELOW_FINISH();
1993 }
1994 
1999 void monster_check_apply_all(object *monster) {
2000  if (!monster->head) {
2001  fix_object(monster); // Needed to correctly fill various body fields.
2002  }
2003  FOR_INV_PREPARE(monster, inv)
2004  monster_check_apply(monster, inv);
2005  FOR_INV_FINISH();
2006 }
2007 
2012 void monster_npc_call_help(object *op) {
2013  const char *value;
2014  int help_radius = 3;
2015 
2016  value = object_get_value(op, "help_radius");
2017  if ( value ) {
2018  int override_help_radius;
2019 
2020  override_help_radius = strtol(value, NULL, 10);
2021  if (override_help_radius >= 0 && override_help_radius < 30)
2022  help_radius = override_help_radius;
2023  else
2024  LOG(llevDebug, "monster_npc_call_help: invalid help_radius %d\n", override_help_radius);
2025  }
2026 
2027  for (int x = -help_radius; x <= help_radius; x++)
2028  for (int y = -help_radius; y <= help_radius; y++) {
2029  mapstruct *m = op->map;
2030  int16_t sx = op->x+x;
2031  int16_t sy = op->y+y;
2032  int mflags = get_map_flags(m, &m, sx, sy, &sx, &sy);
2033  /* If nothing alive on this space, no need to search the space. */
2034  if ((mflags&P_OUT_OF_MAP) || !(mflags&P_IS_ALIVE))
2035  continue;
2036 
2037  FOR_MAP_PREPARE(m, sx, sy, npc)
2039  object_set_enemy(npc, op->enemy);
2041  }
2042  FOR_MAP_FINISH();
2043  }
2044 }
2045 
2054 static int monster_dist_att(int dir, object *enemy, object *part, rv_vector *rv) {
2055  if (monster_can_hit(part, enemy, rv))
2056  return dir;
2057  if (rv->distance < 10)
2058  return absdir(dir+4);
2059  else if (rv->distance > 18)
2060  return dir;
2061  return 0;
2062 }
2063 
2073 static int monster_run_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv) {
2074  if ((monster_can_hit(part, enemy, rv) && ob->move_status < 20) || ob->move_status < 20) {
2075  ob->move_status++;
2076  return (dir);
2077  } else if (ob->move_status > 20)
2078  ob->move_status = 0;
2079  return absdir(dir+4);
2080 }
2081 
2088 static int monster_hitrun_att(int dir, object *ob) {
2089  if (ob->move_status++ < 25)
2090  return dir;
2091  else if (ob->move_status < 50)
2092  return absdir(dir+4);
2093  ob->move_status = 0;
2094  return absdir(dir+4);
2095 }
2096 
2106 static int monster_wait_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv) {
2107  int inrange = monster_can_hit(part, enemy, rv);
2108 
2109  if (ob->move_status || inrange)
2110  ob->move_status++;
2111 
2112  if (ob->move_status == 0)
2113  return 0;
2114  else if (ob->move_status < 10)
2115  return dir;
2116  else if (ob->move_status < 15)
2117  return absdir(dir+4);
2118  ob->move_status = 0;
2119  return 0;
2120 }
2121 
2131 static int monster_disthit_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv) {
2132  /* The logic below here looked plain wrong before. Basically, what should
2133  * happen is that if the creatures hp percentage falls below run_away,
2134  * the creature should run away (dir+4)
2135  * I think its wrong for a creature to have a zero maxhp value, but
2136  * at least one map has this set, and whatever the map contains, the
2137  * server should try to be resilant enough to avoid the problem
2138  */
2139  if (ob->stats.maxhp && (ob->stats.hp*100)/ob->stats.maxhp < ob->run_away)
2140  return absdir(dir+4);
2141  return monster_dist_att(dir, enemy, part, rv);
2142 }
2143 
2150 static int monster_wait_att2(int dir, rv_vector *rv) {
2151  if (rv->distance < 9)
2152  return absdir(dir+4);
2153  return 0;
2154 }
2155 
2160 static void monster_circ1_move(object *ob) {
2161  static const int circle [12] = { 3, 3, 4, 5, 5, 6, 7, 7, 8, 1, 1, 2 };
2162 
2163  if (++ob->move_status > 11)
2164  ob->move_status = 0;
2165  if (!(move_object(ob, circle[ob->move_status])))
2166  (void)move_object(ob, RANDOM()%8+1);
2167 }
2168 
2173 static void monster_circ2_move(object *ob) {
2174  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 };
2175 
2176  if (++ob->move_status > 19)
2177  ob->move_status = 0;
2178  if (!(move_object(ob, circle[ob->move_status])))
2179  (void)move_object(ob, RANDOM()%8+1);
2180 }
2181 
2186 static void monster_pace_movev(object *ob) {
2187  if (ob->move_status++ > 6)
2188  ob->move_status = 0;
2189  if (ob->move_status < 4)
2190  (void)move_object(ob, 5);
2191  else
2192  (void)move_object(ob, 1);
2193 }
2194 
2199 static void monster_pace_moveh(object *ob) {
2200  if (ob->move_status++ > 6)
2201  ob->move_status = 0;
2202  if (ob->move_status < 4)
2203  (void)move_object(ob, 3);
2204  else
2205  (void)move_object(ob, 7);
2206 }
2207 
2212 static void monster_pace2_movev(object *ob) {
2213  if (ob->move_status++ > 16)
2214  ob->move_status = 0;
2215  if (ob->move_status < 6)
2216  (void)move_object(ob, 5);
2217  else if (ob->move_status < 8)
2218  return;
2219  else if (ob->move_status < 13)
2220  (void)move_object(ob, 1);
2221 }
2222 
2227 static void monster_pace2_moveh(object *ob) {
2228  if (ob->move_status++ > 16)
2229  ob->move_status = 0;
2230  if (ob->move_status < 6)
2231  (void)move_object(ob, 3);
2232  else if (ob->move_status < 8)
2233  return;
2234  else if (ob->move_status < 13)
2235  (void)move_object(ob, 7);
2236 }
2237 
2242 static void monster_rand_move(object *ob) {
2243  int i;
2244 
2245  if (ob->move_status < 1
2246  || ob->move_status > 8
2247  || !(move_object(ob, ob->move_status || !(RANDOM()%9))))
2248  for (i = 0; i < 5; i++) {
2249  ob->move_status = RANDOM()%8+1;
2250  if (move_object(ob, ob->move_status))
2251  return;
2252  }
2253 }
2254 
2262 void monster_check_earthwalls(object *op, mapstruct *m, int x, int y) {
2263  FOR_MAP_PREPARE(m, x, y, tmp)
2264  if (tmp->type == EARTHWALL) {
2265  hit_player(tmp, op->stats.dam, op, AT_PHYSICAL, 1);
2266  return;
2267  }
2268  FOR_MAP_FINISH();
2269 }
2270 
2278 void monster_check_doors(object *op, mapstruct *m, int x, int y) {
2279  FOR_MAP_PREPARE(m, x, y, tmp)
2280  if (tmp->type == DOOR) {
2281  hit_player(tmp, op->stats.dam, op, AT_PHYSICAL, 1);
2282  return;
2283  }
2284  FOR_MAP_FINISH();
2285 }
2286 
2292 void monster_do_say(const mapstruct *map, const char *message) {
2294  message);
2295 }
2296 
2303 static StringBuffer *monster_format_say(const object* npc, const char *message) {
2304  char name[MAX_BUF];
2305  StringBuffer *buf;
2306 
2307  query_name(npc, name, sizeof(name));
2308  buf = stringbuffer_new();
2309  stringbuffer_append_printf(buf, "%s says: %s", name, message);
2310  return buf;
2311 }
2312 
2319  switch (rt) {
2320  case rt_say:
2321  return "say";
2322  case rt_reply:
2323  return "reply";
2324  case rt_question:
2325  return "ask";
2326  }
2327  assert(0);
2328  return NULL;
2329 }
2330 
2336 static const char *get_reply_text_other(reply_type rt) {
2337  switch (rt) {
2338  case rt_say:
2339  return "says";
2340  case rt_reply:
2341  return "replies";
2342  case rt_question:
2343  return "asks";
2344  }
2345  assert(0);
2346  return NULL;
2347 }
2348 
2374 void monster_communicate(object *op, const char *txt) {
2375  int i, mflags;
2376  int16_t x, y;
2377  mapstruct *mp, *orig_map = op->map;
2378  char own[MAX_BUF], others[MAX_BUF];
2379  talk_info info;
2380 
2381  info.text = txt;
2382  info.message = NULL;
2383  info.replies_count = 0;
2384  info.who = op;
2385  info.npc_msg_count = 0;
2386 
2387  /* Note that this loop looks pretty inefficient to me - we look and try to talk
2388  * to every object within 2 spaces. It would seem that if we trim this down to
2389  * only try to talk to objects with npc->msg set, things would be a lot more efficient,
2390  * but I'm not sure if there are any objects out there that don't have a message and instead
2391  * rely sorely on events - MSW 2009-04-14
2392  */
2393  for (i = 0; i <= SIZEOFFREE2; i++) {
2394  mp = op->map;
2395  x = op->x+freearr_x[i];
2396  y = op->y+freearr_y[i];
2397 
2398  mflags = get_map_flags(mp, &mp, x, y, &x, &y);
2399  if (mflags&P_OUT_OF_MAP)
2400  continue;
2401 
2402  FOR_MAP_PREPARE(mp, x, y, npc) {
2403  monster_talk_to_npc(npc, &info);
2404  if (orig_map != op->map) {
2405  LOG(llevDebug, "Warning: Forced to swap out very recent map\n");
2406  return;
2407  }
2408  } FOR_MAP_FINISH();
2409  }
2410 
2411  /* First, what the player says. */
2412  if (info.message != NULL) {
2413  snprintf(own, sizeof(own), "You %s: %s", get_reply_text_own(info.message_type), info.message);
2414  snprintf(others, sizeof(others), "%s %s: %s", op->name, get_reply_text_other(info.message_type), info.message);
2415  free_string(info.message);
2416  } else {
2417  snprintf(own, sizeof(own), "You say: %s", txt);
2418  snprintf(others, sizeof(others), "%s says: %s", op->name, txt);
2419  }
2422 
2423  /* Then NPCs can actually talk. */
2424  for (i = 0; i < info.npc_msg_count; i++) {
2425  monster_do_say(orig_map, info.npc_msgs[i]);
2426  free_string(info.npc_msgs[i]);
2427  }
2428 
2429  /* Finally, the replies the player can use. */
2430  if (info.replies_count > 0) {
2432  for (i = 0; i < info.replies_count; i++) {
2434  free_string(info.replies_words[i]);
2435  free_string(info.replies[i]);
2436  }
2437  }
2438 }
2439 
2448 static int monster_do_talk_npc(object *npc, talk_info *info) {
2451 
2452  if (!get_dialog_message(npc, info->text, &message, &reply))
2453  return 0;
2454 
2455  if (reply) {
2456  info->message = add_string(reply->message);
2457  info->message_type = reply->type;
2458  }
2459 
2460  if (message->identifies) {
2461  identify(npc);
2462  }
2463 
2464  if (npc->type == MAGIC_EAR) {
2466  use_trigger(npc);
2467  } else {
2468  char value[2];
2469 
2470  if (info->npc_msg_count < MAX_NPC) {
2472  info->npc_msg_count++;
2473  }
2474 
2475  /* mark that the npc was talked to, so it won't move randomly later on */
2476  value[0] = '3' + rand() % 6;
2477  value[1] = '\0';
2478  object_set_value(npc, "talked_to", value, 1);
2479 
2480  reply = message->replies;
2481  while (reply && info->replies_count < MAX_REPLIES) {
2482  info->replies[info->replies_count] = add_string(reply->message);
2483  info->replies_words[info->replies_count] = add_string(reply->reply);
2484  info->replies_count++;
2485  reply = reply->next;
2486  }
2487  }
2488 
2489  return 1;
2490 }
2491 
2497 void monster_npc_say(object *npc, const char *cp) {
2498  char *message;
2500 
2502  monster_do_say(npc->map, message);
2503  free(message);
2504 }
2505 
2514 static int monster_talk_to_npc(object *npc, talk_info *info) {
2515 
2516  if (events_execute_object_say(npc, info) != 0)
2517  return 0;
2518 
2519  /* Here we let the objects inside inventories hear and answer, too. */
2520  /* This allows the existence of "intelligent" weapons you can discuss with */
2521  FOR_INV_PREPARE(npc, cobj)
2522  if (events_execute_object_say(cobj, info) != 0)
2523  return 0;
2524  FOR_INV_FINISH();
2525  if (info->who == npc)
2526  return 0;
2527  return monster_do_talk_npc(npc, info);
2528 }
2529 
2542 object *monster_find_throw_ob(object *op) {
2543  /* New throw code: look through the inventory. Grap the first legal is_thrown
2544  * marked item and throw it to the enemy.
2545  */
2546 
2547  FOR_INV_PREPARE(op, tmp) {
2548  /* Can't throw invisible objects or items that are applied */
2549  if (!tmp->invisible && !QUERY_FLAG(tmp, FLAG_APPLIED) && QUERY_FLAG(tmp, FLAG_IS_THROWN)) {
2550 #ifdef DEBUG_THROW
2551  char what[MAX_BUF];
2552 
2553  query_name(tmp, what, MAX_BUF);
2554  LOG(llevDebug, "%s chooses to throw: %s (%d)\n", op->name, what, tmp->count);
2555 #endif
2556  return tmp;
2557  }
2558  } FOR_INV_FINISH();
2559 
2560 #ifdef DEBUG_THROW
2561  LOG(llevDebug, "%s chooses to throw nothing\n", op->name);
2562 #endif
2563  return NULL;
2564 }
2565 
2581 int monster_can_detect_enemy(object *op, object *enemy, rv_vector *rv) {
2582  int radius = MIN_MON_RADIUS, hide_discovery;
2583 
2584  /* null detection for any of these condtions always */
2585  if (!op || !enemy || !op->map || !enemy->map)
2586  return 0;
2587 
2588  /* If the monster (op) has no way to get to the enemy, do nothing */
2589  if (!get_rangevector(op, enemy, rv, 0))
2590  return 0;
2591 
2592  /* Monsters always ignore the DM */
2593  if (op->type != PLAYER && QUERY_FLAG(enemy, FLAG_WIZ))
2594  return 0;
2595 
2596  /* simple check. Should probably put some range checks in here. */
2597  if (monster_can_see_enemy(op, enemy))
2598  return 1;
2599 
2600  /* The rest of this is for monsters. Players are on their own for
2601  * finding enemies!
2602  */
2603  if (op->type == PLAYER)
2604  return 0;
2605 
2606  /* Quality invisible? Bah, we wont see them w/o SEE_INVISIBLE
2607  * flag (which was already checked) in can_see_enmy (). Lets get out of here
2608  */
2609  if (enemy->invisible && (!enemy->contr || (!enemy->contr->tmp_invis && !enemy->contr->hidden)))
2610  return 0;
2611 
2612  /* use this for invis also */
2613  hide_discovery = op->stats.Int/5;
2614 
2615  /* Determine Detection radii */
2616  if (!enemy->hide) /* to detect non-hidden (eg dark/invis enemy) */
2617  radius = MAX(op->stats.Wis/5+1, MIN_MON_RADIUS);
2618  else { /* a level/INT/Dex adjustment for hiding */
2619  object *sk_hide;
2620  int bonus = (op->level/2)+(op->stats.Int/5);
2621 
2622  if (enemy->type == PLAYER) {
2623  sk_hide = find_skill_by_number(enemy, SK_HIDING);
2624  if (sk_hide != NULL)
2625  bonus -= sk_hide->level;
2626  else {
2627  LOG(llevError, "monster_can_detect_enemy() got hidden player w/o hiding skill!\n");
2628  make_visible(enemy);
2629  radius = MAX(radius, MIN_MON_RADIUS);
2630  }
2631  } else /* enemy is not a player */
2632  bonus -= enemy->level;
2633 
2634  radius += bonus/5;
2635  hide_discovery += bonus*5;
2636  } /* else creature has modifiers for hiding */
2637 
2638  /* Radii stealth adjustment. Only if you are stealthy
2639  * will you be able to sneak up closer to creatures */
2640  if (QUERY_FLAG(enemy, FLAG_STEALTH))
2641  radius = radius/2, hide_discovery = hide_discovery/3;
2642 
2643  /* Radii adjustment for enemy standing in the dark */
2644  if (op->map->darkness > 0 && !monster_stand_in_light(enemy)) {
2645  /* on dark maps body heat can help indicate location with infravision
2646  * undead don't have body heat, so no benefit detecting them.
2647  */
2648  if (QUERY_FLAG(op, FLAG_SEE_IN_DARK) && !is_true_undead(enemy))
2649  radius += op->map->darkness/2;
2650  else
2651  radius -= op->map->darkness/2;
2652 
2653  /* op next to a monster (and not in complete darkness)
2654  * the monster should have a chance to see you.
2655  */
2656  if (radius < MIN_MON_RADIUS && op->map->darkness < 5 && rv->distance <= 1)
2657  radius = MIN_MON_RADIUS;
2658  } /* if on dark map */
2659 
2660  /* Lets not worry about monsters that have incredible detection
2661  * radii, we only need to worry here about things the player can
2662  * (potentially) see. This is 13, as that is the maximum size the player
2663  * may have for their map - in that way, creatures at the edge will
2664  * do something. Note that the distance field in the
2665  * vector is real distance, so in theory this should be 18 to
2666  * find that.
2667  */
2668  if (radius > 13)
2669  radius = 13;
2670 
2671  /* Enemy in range! Now test for detection */
2672  if ((int)rv->distance <= radius) {
2673  /* ah, we are within range, detected? take cases */
2674  if (!enemy->invisible) /* enemy in dark squares... are seen! */
2675  return 1;
2676 
2677  /* hidden or low-quality invisible */
2678  if (enemy->hide && rv->distance <= 1 && RANDOM()%100 <= (unsigned int)hide_discovery) {
2679  make_visible(enemy);
2680  /* inform players of new status */
2681  if (enemy->type == PLAYER && player_can_view(enemy, op))
2683  "You are discovered by %s!",
2684  op->name);
2685  return 1; /* detected enemy */
2686  } else if (enemy->invisible) {
2687  /* Change this around - instead of negating the invisible, just
2688  * return true so that the mosnter that managed to detect you can
2689  * do something to you. Decreasing the duration of invisible
2690  * doesn't make a lot of sense IMO, as a bunch of stupid creatures
2691  * can then basically negate the spell. The spell isn't negated -
2692  * they just know where you are!
2693  */
2694  if (RANDOM()%50 <= (unsigned int)hide_discovery) {
2695  if (enemy->type == PLAYER) {
2696  char name[MAX_BUF];
2697 
2700  "You see %s noticing your position.",
2701  name);
2702  }
2703  return 1;
2704  }
2705  }
2706  } /* within range */
2707 
2708  /* Wasn't detected above, so still hidden */
2709  return 0;
2710 }
2711 
2722  if (!op)
2723  return 0;
2724  if (op->glow_radius > 0)
2725  return 1;
2726 
2727  if (op->map) {
2728  int x, y;
2729 
2730  /* Check the spaces with the max light radius to see if any of them
2731  * have lights, and if any of them light the player enough, then return 1.
2732  */
2733  for (x = op->x-MAX_LIGHT_RADII; x <= op->x+MAX_LIGHT_RADII; x++) {
2734  for (y = op->y-MAX_LIGHT_RADII; y <= op->y+MAX_LIGHT_RADII; y++) {
2735  int16_t nx = x;
2736  int16_t ny = y;
2737  mapstruct *m = get_map_from_coord(op->map, &nx, &ny);
2738  if (m == nullptr)
2739  continue;
2740 
2741  int light = GET_MAP_LIGHT(m, nx, ny);
2742  if (light == 0)
2743  continue;
2744 
2745  if (ihypot(x-op->x, y-op->y) < light)
2746  return 1;
2747  }
2748  }
2749  }
2750  return 0;
2751 }
2752 
2757  if (!op)
2758  return 0;
2759 
2760  if (op->light_cached_time == pticks)
2761  return op->light_cached;
2762 
2764  op->light_cached = val;
2765  op->light_cached_time = pticks;
2766  return val;
2767 }
2768 
2778 int monster_can_see_enemy(object *op, object *enemy) {
2779  object *looker = HEAD(op);
2780 
2781  /* safety */
2782  if (!looker || !enemy || !QUERY_FLAG(looker, FLAG_ALIVE))
2783  return 0;
2784 
2785  /* we dont give a full treatment of xrays here (shorter range than normal,
2786  * see through walls). Should we change the code elsewhere to make you
2787  * blind even if you can xray?
2788  */
2789  if (QUERY_FLAG(looker, FLAG_BLIND) && !QUERY_FLAG(looker, FLAG_XRAYS))
2790  return 0;
2791 
2792  /* checking for invisible things */
2793  if (enemy->invisible) {
2794  /* HIDDEN ENEMY. by definition, you can't see hidden stuff!
2795  * However, if you carry any source of light, then the hidden
2796  * creature is seeable (and stupid) */
2797  if (has_carried_lights(enemy)) {
2798  if (enemy->hide) {
2799  make_visible(enemy);
2801  "Your light reveals your hiding spot!");
2802  }
2803  return 1;
2804  } else if (enemy->hide)
2805  return 0;
2806 
2807  /* Invisible enemy. Break apart the check for invis undead/invis looker
2808  * into more simple checks - the QUERY_FLAG doesn't return 1/0 values,
2809  * and making it a conditional makes the code pretty ugly.
2810  */
2811  if (!QUERY_FLAG(looker, FLAG_SEE_INVISIBLE)) {
2812  if (makes_invisible_to(enemy, looker))
2813  return 0;
2814  }
2815  } else if (looker->type == PLAYER) /* for players, a (possible) shortcut */
2816  if (player_can_view(looker, enemy))
2817  return 1;
2818 
2819  /* ENEMY IN DARK MAP. Without infravision, the enemy is not seen
2820  * unless they carry a light or stand in light. Darkness doesnt
2821  * inhibit the undead per se (but we should give their archs
2822  * CAN_SEE_IN_DARK, this is just a safety
2823  * we care about the enemy maps status, not the looker.
2824  * only relevant for tiled maps, but it is possible that the
2825  * enemy is on a bright map and the looker on a dark - in that
2826  * case, the looker can still see the enemy
2827  */
2828  if (enemy->map->darkness > 0
2829  && !monster_stand_in_light(enemy)
2830  && (!QUERY_FLAG(looker, FLAG_SEE_IN_DARK) || !is_true_undead(looker) || !QUERY_FLAG(looker, FLAG_XRAYS)))
2831  return 0;
2832 
2833  return 1;
2834 }
object_value_set
bool object_value_set(const object *op, const char *const key)
Definition: object.cpp:4376
FLAG_USE_BOW
#define FLAG_USE_BOW
Definition: define.h:293
GET_MAP_OB
#define GET_MAP_OB(M, X, Y)
Definition: map.h:170
do_skill
int do_skill(object *op, object *part, object *skill, int dir, const char *string)
Definition: skill_util.cpp:431
TRIGGER
@ TRIGGER
Definition: object.h:134
PLAYER
@ PLAYER
Definition: object.h:112
object_get_owner
object * object_get_owner(object *op)
Definition: object.cpp:804
path_to_player
int path_to_player(object *mon, object *pl, unsigned mindiff)
Definition: player.cpp:651
monster_pace2_movev
static void monster_pace2_movev(object *ob)
Definition: monster.cpp:2212
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.cpp:329
global.h
FLAG_NEUTRAL
#define FLAG_NEUTRAL
Definition: define.h:354
estimate_distance
static uint16_t estimate_distance(int16_t ax, int16_t ay, int16_t bx, int16_t by)
Definition: monster.cpp:441
object_find_by_type_subtype
object * object_find_by_type_subtype(const object *who, int type, int subtype)
Definition: object.cpp:4301
SP_BOLT
#define SP_BOLT
Definition: spells.h:78
CF_HANDLE
@ CF_HANDLE
Definition: object.h:213
talk_info::replies
sstring replies[MAX_REPLIES]
Definition: dialog.h:57
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Definition: define.h:730
remove_friendly_object
void remove_friendly_object(object *op)
Definition: friend.cpp:52
object_find_by_type_applied
object * object_find_by_type_applied(const object *who, int type)
Definition: object.cpp:4083
NUM_BODY_LOCATIONS
#define NUM_BODY_LOCATIONS
Definition: object.h:15
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:123
WAITATT
#define WAITATT
Definition: define.h:495
llevError
@ llevError
Definition: logger.h:11
FABS
#define FABS(x)
Definition: define.h:22
find_skill_by_number
object * find_skill_by_number(object *who, int skillno)
Definition: main.cpp:375
SP_BOMB
#define SP_BOMB
Definition: spells.h:82
WAND
@ WAND
Definition: object.h:225
FLAG_USE_RING
#define FLAG_USE_RING
Definition: define.h:297
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:58
ALLRUN
#define ALLRUN
Definition: define.h:497
talk_info::replies_words
sstring replies_words[MAX_REPLIES]
Definition: dialog.h:56
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
talk_info::npc_msg_count
int npc_msg_count
Definition: dialog.h:58
CAN_APPLY_NOT_MASK
#define CAN_APPLY_NOT_MASK
Definition: define.h:632
monster_check_apply_all
void monster_check_apply_all(object *monster)
Definition: monster.cpp:1999
FLAG_GENERATOR
#define FLAG_GENERATOR
Definition: define.h:248
object::inv
object * inv
Definition: object.h:298
diamondslots.x
x
Definition: diamondslots.py:15
RUNATT
#define RUNATT
Definition: define.h:493
MSG_TYPE_SKILL
#define MSG_TYPE_SKILL
Definition: newclient.h:410
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
monster_stand_in_light_internal
static int monster_stand_in_light_internal(object *op)
Definition: monster.cpp:2721
PACEV2
#define PACEV2
Definition: define.h:526
monster_disthit_att
static int monster_disthit_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv)
Definition: monster.cpp:2131
pets_should_arena_attack
int pets_should_arena_attack(object *pet, object *owner, object *target)
Definition: pets.cpp:1086
path_data
Definition: monster.cpp:413
make_visible
void make_visible(object *op)
Definition: player.cpp:3960
stringbuffer_append_printf
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
Definition: stringbuffer.cpp:138
WILL_APPLY_HANDLE
#define WILL_APPLY_HANDLE
Definition: object.h:54
FLAG_SEE_IN_DARK
#define FLAG_SEE_IN_DARK
Definition: define.h:337
AT_PHYSICAL
#define AT_PHYSICAL
Definition: attack.h:76
object::arch
struct archetype * arch
Definition: object.h:424
cast_spell
int cast_spell(object *op, object *caster, int dir, object *spell_ob, char *stringarg)
Definition: spell_util.cpp:1424
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Definition: stringbuffer.cpp:57
object::attack_movement
uint16_t attack_movement
Definition: object.h:401
absdir
int absdir(int d)
Definition: object.cpp:3714
FOR_BELOW_PREPARE
#define FOR_BELOW_PREPARE(op_, it_)
Definition: define.h:704
object::range
int8_t range
Definition: object.h:417
object_set_enemy
void object_set_enemy(object *op, object *enemy)
Definition: object.cpp:915
GEM
@ GEM
Definition: object.h:172
object::invisible
int16_t invisible
Definition: object.h:370
monster_check_good_weapon
static int monster_check_good_weapon(object *who, object *item)
Definition: monster.cpp:1652
HITRUN
#define HITRUN
Definition: define.h:494
object::x
int16_t x
Definition: object.h:335
player::peaceful
uint32_t peaceful
Definition: player.h:146
monster_check_enemy
object * monster_check_enemy(object *npc, rv_vector *rv)
Definition: monster.cpp:72
object::pick_up
uint8_t pick_up
Definition: object.h:371
object::map
struct mapstruct * map
Definition: object.h:305
WEAPON
@ WEAPON
Definition: object.h:124
monster_run_att
static int monster_run_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv)
Definition: monster.cpp:2073
MinHeap
Definition: minheap.h:16
guildjoin.ob
ob
Definition: guildjoin.py:42
say.reply
string reply
Definition: say.py:77
monster_check_doors
void monster_check_doors(object *op, mapstruct *m, int x, int y)
Definition: monster.cpp:2278
SP_CONE
#define SP_CONE
Definition: spells.h:81
commongive.inv
inv
Definition: commongive.py:29
mapstruct::height
uint16_t height
Definition: map.h:335
FLAG_SEE_INVISIBLE
#define FLAG_SEE_INVISIBLE
Definition: define.h:253
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
monster_check_pickup
static void monster_check_pickup(object *monster)
Definition: monster.cpp:1851
mon
object * mon
Definition: comet_perf.cpp:75
MIN
#define MIN(x, y)
Definition: compat.h:21
TREASURE
@ TREASURE
Definition: object.h:115
SKILL
@ SKILL
Definition: object.h:148
object::direction
int8_t direction
Definition: object.h:344
monster_check_good_armour
static int monster_check_good_armour(object *who, object *item)
Definition: monster.cpp:1699
object::count
tag_t count
Definition: object.h:307
FLAG_SCARED
#define FLAG_SCARED
Definition: define.h:271
fix_object
void fix_object(object *op)
Definition: living.cpp:1132
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:247
RANDO
#define RANDO
Definition: define.h:520
monster_can_hit
static int monster_can_hit(object *ob1, object *ob2, rv_vector *rv)
Definition: monster.cpp:1141
llevMonster
@ llevMonster
Definition: logger.h:14
get_nearest_criminal
object * get_nearest_criminal(object *mon)
Definition: player.cpp:583
ATNR_PHYSICAL
#define ATNR_PHYSICAL
Definition: attack.h:49
player::hidden
uint32_t hidden
Definition: player.h:147
object::enemy
object * enemy
Definition: object.h:391
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
skills.h
rv_vector::part
object * part
Definition: map.h:373
object::hide
uint8_t hide
Definition: object.h:397
apply_manual
int apply_manual(object *op, object *tmp, int aflag)
Definition: apply.cpp:597
FOR_OB_AND_ABOVE_FINISH
#define FOR_OB_AND_ABOVE_FINISH()
Definition: define.h:743
mapstruct::path
char path[HUGE_BUF]
Definition: map.h:353
object_get_value
const char * object_get_value(const object *op, const char *const key)
Definition: object.cpp:4346
P_IS_ALIVE
#define P_IS_ALIVE
Definition: map.h:235
FLAG_APPLIED
#define FLAG_APPLIED
Definition: define.h:235
object::level
int16_t level
Definition: object.h:361
FLAG_STEALTH
#define FLAG_STEALTH
Definition: define.h:312
FLAG_BLIND
#define FLAG_BLIND
Definition: define.h:336
pticks
uint32_t pticks
Definition: time.cpp:47
buf
StringBuffer * buf
Definition: readable.cpp:1565
monster_find_enemy
static object * monster_find_enemy(object *npc, rv_vector *rv)
Definition: monster.cpp:232
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
Definition: object.cpp:2857
object::will_apply
uint8_t will_apply
Definition: object.h:402
PACEH
#define PACEH
Definition: define.h:514
ihypot
int ihypot(int a, int b)
Definition: utils.cpp:570
MAX
#define MAX(x, y)
Definition: compat.h:24
get_nearest_player
object * get_nearest_player(object *mon)
Definition: player.cpp:540
object::resist
int16_t resist[NROFATTACKS]
Definition: object.h:351
mapstruct::width
uint16_t width
Definition: map.h:335
monster_rand_move
static void monster_rand_move(object *ob)
Definition: monster.cpp:2242
talk_info::message
sstring message
Definition: dialog.h:53
FOR_BELOW_FINISH
#define FOR_BELOW_FINISH()
Definition: define.h:711
talk_info::replies_count
int replies_count
Definition: dialog.h:55
FLAG_ALIVE
#define FLAG_ALIVE
Definition: define.h:230
monster_find_nearest_enemy
object * monster_find_nearest_enemy(object *npc, object *owner)
Definition: monster.cpp:175
rv_vector::distance_y
int distance_y
Definition: map.h:371
FOR_OB_AND_ABOVE_PREPARE
#define FOR_OB_AND_ABOVE_PREPARE(op_)
Definition: define.h:739
object::carrying
int32_t carrying
Definition: object.h:377
SP_SUMMON_MONSTER
#define SP_SUMMON_MONSTER
Definition: spells.h:101
monster_wait_att2
static int monster_wait_att2(int dir, rv_vector *rv)
Definition: monster.cpp:2150
object::y
int16_t y
Definition: object.h:335
object_find_by_type_and_race
object * object_find_by_type_and_race(const object *who, int type, const char *race)
Definition: object.cpp:4133
m
static event_registration m
Definition: citylife.cpp:425
rv_vector::distance_x
int distance_x
Definition: map.h:370
autojail.who
who
Definition: autojail.py:3
stringbuffer_finish
char * stringbuffer_finish(StringBuffer *sb)
Definition: stringbuffer.cpp:76
FLAG_NO_ATTACK
#define FLAG_NO_ATTACK
Definition: define.h:355
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.cpp:1560
object::contr
struct player * contr
Definition: object.h:284
object::chosen_skill
object * chosen_skill
Definition: object.h:396
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.cpp:54
object::subtype
uint8_t subtype
Definition: object.h:349
add_refcount
sstring add_refcount(sstring str)
Definition: shstr.cpp:210
minheap.h
freearr_y
short freearr_y[SIZEOFFREE]
Definition: object.cpp:305
monster_wait_att
static int monster_wait_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv)
Definition: monster.cpp:2106
monster_get_armour_quality
static int monster_get_armour_quality(const object *item)
Definition: monster.cpp:1678
query_name
void query_name(const object *op, char *buf, size_t size)
Definition: item.cpp:588
FLAG_USE_RANGE
#define FLAG_USE_RANGE
Definition: define.h:292
FLAG_RUN_AWAY
#define FLAG_RUN_AWAY
Definition: define.h:280
can_see_monsterP
int can_see_monsterP(mapstruct *m, int x, int y, int dir)
Definition: object.cpp:3822
monster_get_weapon_quality
static int monster_get_weapon_quality(const object *item)
Definition: monster.cpp:1626
MOVE_WALK
#define MOVE_WALK
Definition: define.h:392
stringbuffer_finish_shared
sstring stringbuffer_finish_shared(StringBuffer *sb)
Definition: stringbuffer.cpp:85
archetype::clone
object clone
Definition: object.h:487
monster_can_see_enemy
int monster_can_see_enemy(object *op, object *enemy)
Definition: monster.cpp:2778
add_string
sstring add_string(const char *str)
Definition: shstr.cpp:124
monster_apply_below
static void monster_apply_below(object *monster)
Definition: monster.cpp:1976
HEAD
#define HEAD(op)
Definition: object.h:607
ROD
@ ROD
Definition: object.h:114
object::move_type
MoveType move_type
Definition: object.h:436
NDI_DELAYED
#define NDI_DELAYED
Definition: newclient.h:272
ext_info_map
void void ext_info_map(int color, const mapstruct *map, uint8_t type, uint8_t subtype, const char *str1)
Definition: main.cpp:334
FLAG_FREED
#define FLAG_FREED
Definition: define.h:233
path_measure_func
int path_measure_func(const void *ob)
Definition: monster.cpp:431
SPELL_GRACE
#define SPELL_GRACE
Definition: spells.h:59
object::face
const Face * face
Definition: object.h:341
path_data::movement_penalty
int16_t movement_penalty
Definition: monster.cpp:419
AP_IGNORE_CURSE
#define AP_IGNORE_CURSE
Definition: define.h:582
monster_circ2_move
static void monster_circ2_move(object *ob)
Definition: monster.cpp:2173
path_data::x
int16_t x
Definition: monster.cpp:414
has_carried_lights
int has_carried_lights(const object *op)
Definition: los.cpp:346
MIN_MON_RADIUS
#define MIN_MON_RADIUS
Definition: monster.cpp:56
struct_dialog_reply
Definition: dialog.h:16
monster_pace2_moveh
static void monster_pace2_moveh(object *ob)
Definition: monster.cpp:2227
MAX_NPC
#define MAX_NPC
Definition: dialog.h:45
CIRCLE2
#define CIRCLE2
Definition: define.h:513
player::tmp_invis
uint32_t tmp_invis
Definition: player.h:140
object::type
uint8_t type
Definition: object.h:348
monster_pace_moveh
static void monster_pace_moveh(object *ob)
Definition: monster.cpp:2199
SP_SMITE
#define SP_SMITE
Definition: spells.h:84
living::dam
int16_t dam
Definition: living.h:46
FLAG_PARALYZED
#define FLAG_PARALYZED
Definition: define.h:371
FLAG_USE_SHIELD
#define FLAG_USE_SHIELD
Definition: define.h:237
rt_say
@ rt_say
Definition: dialog.h:8
GET_MAP_MOVE_BLOCK
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Definition: map.h:190
FOR_INV_FINISH
#define FOR_INV_FINISH()
Definition: define.h:677
is_enemy
static int is_enemy(object *who, object *owner)
Definition: monster.cpp:142
GOLEM
@ GOLEM
Definition: object.h:150
apply_can_apply_object
int apply_can_apply_object(const object *who, const object *op)
Definition: apply.cpp:1016
FLAG_UNAGGRESSIVE
#define FLAG_UNAGGRESSIVE
Definition: define.h:272
monster_choose_random_spell
static object * monster_choose_random_spell(object *monster)
Definition: monster.cpp:1227
FLAG_USE_WEAPON
#define FLAG_USE_WEAPON
Definition: define.h:296
sproto.h
ARROW
@ ARROW
Definition: object.h:122
IS_SHIELD
#define IS_SHIELD(op)
Definition: define.h:170
GET_MAP_LIGHT
#define GET_MAP_LIGHT(M, X, Y)
Definition: map.h:162
living::sp
int16_t sp
Definition: living.h:42
get_map_from_coord
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
Definition: map.cpp:2321
FLAG_CAN_USE_SKILL
#define FLAG_CAN_USE_SKILL
Definition: define.h:321
rt_reply
@ rt_reply
Definition: dialog.h:9
PACEV
#define PACEV
Definition: define.h:524
monster_can_pick
static int monster_can_pick(object *monster, object *item)
Definition: monster.cpp:1895
living::Int
int8_t Int
Definition: living.h:36
SP_level_spellpoint_cost
int16_t SP_level_spellpoint_cost(object *caster, object *spell, int flags)
Definition: spell_util.cpp:236
monster_format_say
static StringBuffer * monster_format_say(const object *npc, const char *message)
Definition: monster.cpp:2303
monster_compute_path
int monster_compute_path(object *source, object *target, int default_dir)
Definition: monster.cpp:463
object::facing
int8_t facing
Definition: object.h:345
object::animation
const Animations * animation
Definition: object.h:428
monster_find_throw_ob
object * monster_find_throw_ob(object *op)
Definition: monster.cpp:2542
RING
@ RING
Definition: object.h:190
ob_blocked
int ob_blocked(const object *ob, mapstruct *m, int16_t x, int16_t y)
Definition: map.cpp:479
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
fatal
void fatal(enum fatal_error err)
Definition: utils.cpp:590
monster_hitrun_att
static int monster_hitrun_att(int dir, object *ob)
Definition: monster.cpp:2088
monster_npc_call_help
void monster_npc_call_help(object *op)
Definition: monster.cpp:2012
SIZEOFFREE
#define SIZEOFFREE
Definition: define.h:155
P_OUT_OF_MAP
#define P_OUT_OF_MAP
Definition: map.h:247
MAX_BUF
#define MAX_BUF
Definition: define.h:35
monster_use_range
static int monster_use_range(object *head, object *part, object *pl, int dir)
Definition: monster.cpp:1493
MSG_TYPE_DIALOG
#define MSG_TYPE_DIALOG
Definition: newclient.h:403
minheap_remove
void * minheap_remove(MinHeap *heap)
Definition: minheap.cpp:209
object::head
object * head
Definition: object.h:304
IS_WEAPON
#define IS_WEAPON(op)
Definition: define.h:163
get_weight_limit
uint32_t get_weight_limit(int stat)
Definition: living.cpp:2369
use_trigger
void use_trigger(object *op)
Definition: button.cpp:254
object::weight
int32_t weight
Definition: object.h:375
talk_info::text
const char * text
Definition: dialog.h:52
free_string
void free_string(sstring str)
Definition: shstr.cpp:280
living::wc
int8_t wc
Definition: living.h:37
pets_move
void pets_move(object *ob)
Definition: pets.cpp:317
RANDOM
#define RANDOM()
Definition: define.h:644
HI4
#define HI4
Definition: define.h:531
move_object
int move_object(object *op, int dir)
Definition: move.cpp:39
SK_HIDING
@ SK_HIDING
Definition: skills.h:21
StringBuffer
Definition: stringbuffer.cpp:25
MOVE_FLY_LOW
#define MOVE_FLY_LOW
Definition: define.h:393
SP_MAGIC_WALL
#define SP_MAGIC_WALL
Definition: spells.h:89
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:723
SP_INVISIBLE
#define SP_INVISIBLE
Definition: spells.h:93
OUT_OF_REAL_MAP
#define OUT_OF_REAL_MAP(M, X, Y)
Definition: map.h:215
MAGIC_EAR
@ MAGIC_EAR
Definition: object.h:136
get_search_arr
void get_search_arr(int *search_arr)
Definition: object.cpp:3642
living::Wis
int8_t Wis
Definition: living.h:36
MAX_KNOWN_SPELLS
#define MAX_KNOWN_SPELLS
Definition: monster.cpp:1210
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.cpp:415
reply_type
reply_type
Definition: dialog.h:7
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.cpp:219
talk_info::message_type
reply_type message_type
Definition: dialog.h:54
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:265
monster_circ1_move
static void monster_circ1_move(object *ob)
Definition: monster.cpp:2160
FLAG_FRIENDLY
#define FLAG_FRIENDLY
Definition: define.h:246
spells.h
guildbuy.ob1
ob1
Definition: guildbuy.py:22
struct_dialog_message
Definition: dialog.h:26
object::name
sstring name
Definition: object.h:319
MSG_TYPE_SKILL_FAILURE
#define MSG_TYPE_SKILL_FAILURE
Definition: newclient.h:593
monster_move_no_enemy
static int monster_move_no_enemy(object *op)
Definition: monster.cpp:782
get_dialog_message
int get_dialog_message(object *op, const char *text, struct_dialog_message **message, struct_dialog_reply **reply)
Definition: dialog.cpp:213
object::spellitem
object * spellitem
Definition: object.h:406
path_data::distance
uint16_t distance
Definition: monster.cpp:416
SIZEOFFREE2
#define SIZEOFFREE2
Definition: define.h:154
MAX_REPLIES
#define MAX_REPLIES
Definition: dialog.h:43
object_can_pick
int object_can_pick(const object *who, const object *item)
Definition: object.cpp:3867
IS_ARMOR
#define IS_ARMOR(op)
Definition: define.h:166
monster_can_detect_enemy
int monster_can_detect_enemy(object *op, object *enemy, rv_vector *rv)
Definition: monster.cpp:2581
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.cpp:300
monster_do_say
void monster_do_say(const mapstruct *map, const char *message)
Definition: monster.cpp:2292
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:149
SP_MOVING_BALL
#define SP_MOVING_BALL
Definition: spells.h:109
mapstruct
Definition: map.h:313
sstring
const typedef char * sstring
Definition: sstring.h:2
rt_question
@ rt_question
Definition: dialog.h:10
give.op
op
Definition: give.py:33
autojail.value
value
Definition: autojail.py:6
animate_object
void animate_object(object *op, int dir)
Definition: anim.cpp:44
object_split
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
Definition: object.cpp:2637
monster_move_randomly
static int monster_move_randomly(object *op)
Definition: monster.cpp:375
monster_move
int monster_move(object *op)
Definition: monster.cpp:854
monster_use_skill
static int monster_use_skill(object *head, object *part, object *pl, int dir)
Definition: monster.cpp:1436
object::attacked_by_count
tag_t attacked_by_count
Definition: object.h:393
monster_use_bow
static int monster_use_bow(object *head, object *part, object *pl, int dir)
Definition: monster.cpp:1569
pets_follow_owner
void pets_follow_owner(object *ob, object *owner)
Definition: pets.cpp:284
rv_vector
Definition: map.h:368
hit_player
int hit_player(object *op, int dam, object *hitter, uint32_t type, int full_hit)
Definition: attack.cpp:1903
get_randomized_dir
int get_randomized_dir(int dir)
Definition: utils.cpp:412
do_hidden_move
void do_hidden_move(object *op)
Definition: player.cpp:4037
diamondslots.y
y
Definition: diamondslots.py:16
NDI_WHITE
#define NDI_WHITE
Definition: newclient.h:246
on_same_map
int on_same_map(const object *op1, const object *op2)
Definition: map.cpp:2598
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
AP_NOPRINT
#define AP_NOPRINT
Definition: define.h:585
talk_info
Definition: dialog.h:50
object::attacked_by
object * attacked_by
Definition: object.h:392
MSG_TYPE_DIALOG_MAGIC_EAR
#define MSG_TYPE_DIALOG_MAGIC_EAR
Definition: newclient.h:492
minheap_init_static
void minheap_init_static(MinHeap *heap, void **arr, int amt, int(*measure_func)(const void *))
Definition: minheap.cpp:162
MSG_TYPE_DIALOG_NPC
#define MSG_TYPE_DIALOG_NPC
Definition: newclient.h:490
fire_bow
int fire_bow(object *op, object *arrow, int dir, int wc_mod, int16_t sx, int16_t sy)
Definition: player.cpp:2093
get_rangevector
int get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags)
Definition: map.cpp:2492
monster_pace_movev
static void monster_pace_movev(object *ob)
Definition: monster.cpp:2186
talk_info::npc_msgs
sstring npc_msgs[MAX_NPC]
Definition: dialog.h:59
npc_dialog.npc
npc
Definition: npc_dialog.py:95
make_face_from_files.int
int
Definition: make_face_from_files.py:32
MIN_ACTIVE_SPEED
#define MIN_ACTIVE_SPEED
Definition: define.h:639
object::body_info
int8_t body_info[NUM_BODY_LOCATIONS]
Definition: object.h:382
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.cpp:308
FLAG_BERSERK
#define FLAG_BERSERK
Definition: define.h:352
FOOD
@ FOOD
Definition: object.h:117
monster_stand_in_light
int monster_stand_in_light(object *op)
Definition: monster.cpp:2756
object_remove
void object_remove(object *op)
Definition: object.cpp:1833
monster_do_living
void monster_do_living(object *op)
Definition: monster.cpp:719
DOOR
@ DOOR
Definition: object.h:131
player_can_view
int player_can_view(object *pl, object *op)
Definition: player.cpp:4146
FLAG_UNPAID
#define FLAG_UNPAID
Definition: define.h:236
SP_SUMMON_GOLEM
#define SP_SUMMON_GOLEM
Definition: spells.h:86
WAIT2
#define WAIT2
Definition: define.h:499
path_data::heuristic_dist
uint16_t heuristic_dist
Definition: monster.cpp:417
monster_npc_say
void monster_npc_say(object *npc, const char *cp)
Definition: monster.cpp:2497
FLAG_READY_RANGE
#define FLAG_READY_RANGE
Definition: define.h:298
SCROLL
@ SCROLL
Definition: object.h:226
monster_talk_to_npc
static int monster_talk_to_npc(object *npc, talk_info *info)
Definition: monster.cpp:2514
DISTHIT
#define DISTHIT
Definition: define.h:498
FLAG_XRAYS
#define FLAG_XRAYS
Definition: define.h:300
RUSH
#define RUSH
Definition: define.h:496
PETMOVE
#define PETMOVE
Definition: define.h:501
monster_use_scroll
static int monster_use_scroll(object *head, object *part, object *pl, int dir)
Definition: monster.cpp:1352
object::stats
living stats
Definition: object.h:378
object_set_value
int object_set_value(object *op, const char *key, const char *value, int add_key)
Definition: object.cpp:4499
object::more
object * more
Definition: object.h:303
MSG_TYPE_COMMUNICATION
#define MSG_TYPE_COMMUNICATION
Definition: newclient.h:413
get_attr_value
int8_t get_attr_value(const living *stats, int attr)
Definition: living.cpp:313
drain_rod_charge
void drain_rod_charge(object *rod)
Definition: spell_util.cpp:776
DISTATT
#define DISTATT
Definition: define.h:491
WILL_APPLY_TREASURE
#define WILL_APPLY_TREASURE
Definition: object.h:55
minheap_insert
int minheap_insert(MinHeap *heap, void *ob)
Definition: minheap.cpp:184
freearr_x
short freearr_x[SIZEOFFREE]
Definition: object.cpp:299
MAX_EXPLORE
#define MAX_EXPLORE
Definition: monster.cpp:408
monster_cast_spell
static int monster_cast_spell(object *head, object *part, object *pl, int dir)
Definition: monster.cpp:1265
SPELL
@ SPELL
Definition: object.h:219
events_execute_object_say
int events_execute_object_say(object *npc, talk_info *talk)
Definition: events.cpp:303
replace.current
current
Definition: replace.py:64
mapstruct::darkness
uint8_t darkness
Definition: map.h:334
SP_SWARM
#define SP_SWARM
Definition: spells.h:110
OUT_OF_MEMORY
@ OUT_OF_MEMORY
Definition: define.h:48
FLAG_USE_SCROLL
#define FLAG_USE_SCROLL
Definition: define.h:291
CIRCLE1
#define CIRCLE1
Definition: define.h:509
rv_vector::direction
int direction
Definition: map.h:372
dirdiff
int dirdiff(int dir1, int dir2)
Definition: object.cpp:3732
makes_invisible_to
int makes_invisible_to(object *pl, object *mon)
Definition: spell_effect.cpp:756
altar_valkyrie.pl
pl
Definition: altar_valkyrie.py:28
PACEH2
#define PACEH2
Definition: define.h:516
SP_EXPLOSION
#define SP_EXPLOSION
Definition: spells.h:80
FLAG_IS_THROWN
#define FLAG_IS_THROWN
Definition: define.h:249
THROWN_OBJ
@ THROWN_OBJ
Definition: object.h:151
FLAG_SLEEP
#define FLAG_SLEEP
Definition: define.h:307
SK_THROWING
@ SK_THROWING
Definition: skills.h:44
rv_vector::distance
unsigned int distance
Definition: map.h:369
SPELLBOOK
@ SPELLBOOK
Definition: object.h:208
NUM_STATS
@ NUM_STATS
Definition: living.h:18
monster_check_earthwalls
void monster_check_earthwalls(object *op, mapstruct *m, int x, int y)
Definition: monster.cpp:2262
get_reply_text_own
const char * get_reply_text_own(reply_type rt)
Definition: monster.cpp:2318
monster_dist_att
static int monster_dist_att(int dir, object *enemy, object *part, rv_vector *rv)
Definition: monster.cpp:2054
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:670
MSG_TYPE_COMMUNICATION_SAY
#define MSG_TYPE_COMMUNICATION_SAY
Definition: newclient.h:626
drain_wand_charge
void drain_wand_charge(object *wand)
Definition: spell_util.cpp:786
monster_should_cast_spell
static int monster_should_cast_spell(object *spell_ob)
Definition: monster.cpp:1184
MAX_LIGHT_RADII
#define MAX_LIGHT_RADII
Definition: define.h:450
monster_communicate
void monster_communicate(object *op, const char *txt)
Definition: monster.cpp:2374
WILL_APPLY_FOOD
#define WILL_APPLY_FOOD
Definition: object.h:58
llevDebug
@ llevDebug
Definition: logger.h:13
MONEY
@ MONEY
Definition: object.h:142
RANDO2
#define RANDO2
Definition: define.h:523
monster_do_talk_npc
static int monster_do_talk_npc(object *npc, talk_info *info)
Definition: monster.cpp:2448
monster_check_apply
static void monster_check_apply(object *mon, object *item)
Definition: monster.cpp:1734
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Definition: define.h:302
is_true_undead
int is_true_undead(object *op)
Definition: player.cpp:3979
talk_info::who
struct object * who
Definition: dialog.h:51
give.name
name
Definition: give.py:27
living::Str
int8_t Str
Definition: living.h:36
skill_attack
void skill_attack(object *tmp, object *pl, int dir, const char *string, object *skill)
Definition: skill_util.cpp:1270
SPELL_MANA
#define SPELL_MANA
Definition: spells.h:58
identify
object * identify(object *op)
Definition: item.cpp:1421
SP_AURA
#define SP_AURA
Definition: spells.h:120
get_reply_text_other
static const char * get_reply_text_other(reply_type rt)
Definition: monster.cpp:2336