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