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 typedef struct {
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 } path_data;
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  if (spell_ob->subtype == SP_BOLT
1191  || spell_ob->subtype == SP_BULLET
1192  || spell_ob->subtype == SP_EXPLOSION
1193  || spell_ob->subtype == SP_CONE
1194  || spell_ob->subtype == SP_BOMB
1195  || spell_ob->subtype == SP_SMITE
1196  || spell_ob->subtype == SP_MAGIC_MISSILE
1197  || spell_ob->subtype == SP_SUMMON_GOLEM
1198  || spell_ob->subtype == SP_MAGIC_WALL
1199  || spell_ob->subtype == SP_SUMMON_MONSTER
1200  || spell_ob->subtype == SP_MOVING_BALL
1201  || spell_ob->subtype == SP_SWARM
1202  || spell_ob->subtype == SP_INVISIBLE)
1203  return 1;
1204 
1205  return 0;
1206 }
1207 
1209 #define MAX_KNOWN_SPELLS 20
1210 
1226 static object *monster_choose_random_spell(object *monster) {
1227  object *altern[MAX_KNOWN_SPELLS];
1228  int i = 0;
1229 
1230  FOR_INV_PREPARE(monster, tmp)
1231  if (tmp->type == SPELLBOOK || tmp->type == SPELL) {
1232  /* Check and see if it's actually a useful spell.
1233  * If its a spellbook, the spell is actually the inventory item.
1234  * if it is a spell, then it is just the object itself.
1235  */
1236  if (monster_should_cast_spell(tmp->type == SPELLBOOK ? tmp->inv : tmp)) {
1237  altern[i++] = tmp;
1238  if (i == MAX_KNOWN_SPELLS)
1239  break;
1240  }
1241  }
1242  FOR_INV_FINISH();
1243  if (!i)
1244  return NULL;
1245  return altern[RANDOM()%i];
1246 }
1247 
1264 static int monster_cast_spell(object *head, object *part, object *pl, int dir) {
1265  object *spell_item;
1266  object *owner;
1267  rv_vector rv1;
1268 
1269  /* If you want monsters to cast spells over friends, this spell should
1270  * be removed. It probably should be in most cases, since monsters still
1271  * don't care about residual effects (ie, casting a cone which may have a
1272  * clear path to the player, the side aspects of the code will still hit
1273  * other monsters)
1274  */
1275  dir = path_to_player(part, pl, 0);
1276  if (dir == 0)
1277  return 0;
1278 
1279  if (QUERY_FLAG(head, FLAG_FRIENDLY)) {
1280  owner = object_get_owner(head);
1281  if (owner != NULL) {
1282  if (get_rangevector(head, owner, &rv1, 0x1)
1283  && dirdiff(dir, rv1.direction) < 2) {
1284  return 0; /* Might hit owner with spell */
1285  }
1286  }
1287  }
1288 
1289  if (QUERY_FLAG(head, FLAG_CONFUSED))
1290  dir = get_randomized_dir(dir);
1291 
1292  /* If the monster hasn't already chosen a spell, choose one
1293  * I'm not sure if it really make sense to pre-select spells (events
1294  * could be different by the time the monster goes again).
1295  */
1296  if (head->spellitem == NULL) {
1297  spell_item = monster_choose_random_spell(head);
1298  if (spell_item == NULL) {
1299  LOG(llevMonster, "Turned off spells in %s\n", head->name);
1300  CLEAR_FLAG(head, FLAG_CAST_SPELL); /* Will be turned on when picking up book */
1301  return 0;
1302  }
1303  if (spell_item->type == SPELLBOOK) {
1304  if (!spell_item->inv) {
1305  LOG(llevError, "spellbook %s does not contain a spell?\n", spell_item->name);
1306  return 0;
1307  }
1308  spell_item = spell_item->inv;
1309  }
1310  } else
1311  spell_item = head->spellitem;
1312 
1313  if (!spell_item)
1314  return 0;
1315 
1316  /* Best guess this is a defensive/healing spell */
1317  if (spell_item->range <= 1 || spell_item->stats.dam < 0)
1318  dir = 0;
1319 
1320  /* Monster doesn't have enough spell-points */
1321  if (head->stats.sp < SP_level_spellpoint_cost(head, spell_item, SPELL_MANA))
1322  return 0;
1323 
1324  if (head->stats.grace < SP_level_spellpoint_cost(head, spell_item, SPELL_GRACE))
1325  return 0;
1326 
1327  head->stats.sp -= SP_level_spellpoint_cost(head, spell_item, SPELL_MANA);
1328  head->stats.grace -= SP_level_spellpoint_cost(head, spell_item, SPELL_GRACE);
1329 
1330  /* set this to null, so next time monster will choose something different */
1331  head->spellitem = NULL;
1332 
1333  return cast_spell(part, part, dir, spell_item, NULL);
1334 }
1335 
1350 static int monster_use_scroll(object *head, object *part, object *pl, int dir) {
1351  object *scroll;
1352  object *owner;
1353  rv_vector rv1;
1354 
1355  /* If you want monsters to cast spells over friends, this spell should
1356  * be removed. It probably should be in most cases, since monsters still
1357  * don't care about residual effects (ie, casting a cone which may have a
1358  * clear path to the player, the side aspects of the code will still hit
1359  * other monsters)
1360  */
1361  dir = path_to_player(part, pl, 0);
1362  if (dir == 0)
1363  return 0;
1364 
1365  if (QUERY_FLAG(head, FLAG_FRIENDLY)) {
1366  owner = object_get_owner(head);
1367  if (owner != NULL) {
1368  if (get_rangevector(head, owner, &rv1, 0x1)
1369  && dirdiff(dir, rv1.direction) < 2) {
1370  return 0; /* Might hit owner with spell */
1371  }
1372  }
1373  }
1374 
1375  if (QUERY_FLAG(head, FLAG_CONFUSED))
1376  dir = get_randomized_dir(dir);
1377 
1378  scroll = NULL;
1379  FOR_INV_PREPARE(head, tmp)
1380  if (tmp->type == SCROLL && monster_should_cast_spell(tmp->inv)) {
1381  scroll = tmp;
1382  break;
1383  }
1384  FOR_INV_FINISH();
1385 
1386  /* Used up all his scrolls, so nothing do to */
1387  if (!scroll) {
1389  return 0;
1390  }
1391 
1392  /* Spell should be cast on caster (ie, heal, strength) */
1393  if (scroll->inv->range == 0)
1394  dir = 0;
1395 
1396  /* Face the direction that we want to cast. */
1397  head->direction = dir;
1398  head->facing = head->direction;
1399  if (head->animation)
1400  animate_object(head, head->direction);
1401 
1402  apply_manual(part, scroll, 0);
1403  return 1;
1404 }
1405 
1434 static int monster_use_skill(object *head, object *part, object *pl, int dir) {
1435  object *owner;
1436  int found;
1437 
1438  dir = path_to_player(part, pl, 0);
1439  if (dir == 0)
1440  return 0;
1441 
1442  if (QUERY_FLAG(head, FLAG_FRIENDLY)) {
1443  owner = object_get_owner(head);
1444  if (owner != NULL) {
1445  rv_vector rv;
1446 
1447  if (get_rangevector(head, owner, &rv, 0) && dirdiff(dir, rv.direction) < 1)
1448  return 0; /* Might hit owner with skill -thrown rocks for example ?*/
1449  }
1450  }
1451  if (QUERY_FLAG(head, FLAG_CONFUSED))
1452  dir = get_randomized_dir(dir);
1453 
1454  /* skill selection - monster will use the next unused skill.
1455  * well...the following scenario will allow the monster to
1456  * toggle between 2 skills. One day it would be nice to make
1457  * more skills available to monsters.
1458  */
1459  found = 0;
1460  FOR_INV_PREPARE(head, skill)
1461  if (skill->type == SKILL && skill != head->chosen_skill) {
1462  head->chosen_skill = skill;
1463  found = 1;
1464  break;
1465  }
1466  FOR_INV_FINISH();
1467 
1468  if (!found && !head->chosen_skill) {
1469  LOG(llevDebug, "Error: Monster %s (%d) has FLAG_READY_SKILL without skill.\n", head->name, head->count);
1471  return 0;
1472  }
1473  /* use skill */
1474  return do_skill(head, part, head->chosen_skill, dir, NULL);
1475 }
1476 
1491 static int monster_use_range(object *head, object *part, object *pl, int dir) {
1492  object *owner;
1493  int at_least_one = 0;
1494 
1495  dir = path_to_player(part, pl, 0);
1496  if (dir == 0)
1497  return 0;
1498 
1499  if (QUERY_FLAG(head, FLAG_FRIENDLY)) {
1500  owner = object_get_owner(head);
1501  if (owner != NULL) {
1502  rv_vector rv;
1503 
1504  if (get_rangevector(head, owner, &rv, 0) && dirdiff(dir, rv.direction) < 2)
1505  return 0; /* Might hit owner with spell */
1506  }
1507  }
1508  if (QUERY_FLAG(head, FLAG_CONFUSED))
1509  dir = get_randomized_dir(dir);
1510 
1511  FOR_INV_PREPARE(head, wand) {
1512  if (wand->type == WAND) {
1513  /* Found a wand, let's see if it has charges left */
1514  at_least_one = 1;
1515  if (wand->stats.food <= 0)
1516  continue;
1517 
1518  cast_spell(head, wand, dir, wand->inv, NULL);
1519  drain_wand_charge(wand);
1520 
1521  /* Success */
1522  return 1;
1523  }
1524 
1525  if (wand->type == ROD && wand->inv) {
1526  /* Found rod/horn, let's use it if possible */
1527  at_least_one = 1;
1528  if (wand->stats.hp < MAX(wand->inv->stats.sp, wand->inv->stats.grace))
1529  continue;
1530 
1531  /* drain charge before casting spell - can be a case where the
1532  * spell destroys the monster, and rod, so if done after, results
1533  * in crash.
1534  */
1535  drain_rod_charge(wand);
1536  cast_spell(head, wand, dir, wand->inv, NULL);
1537 
1538  /* Success */
1539  return 1;
1540  }
1541  } FOR_INV_FINISH();
1542 
1543  if (at_least_one)
1544  return 0;
1545 
1546  LOG(llevError, "Error: Monster %s (%d) HAS_READY_RANG() without wand/horn/rod.\n", head->name, head->count);
1548  return 0;
1549 }
1550 
1567 static int monster_use_bow(object *head, object *part, object *pl, int dir) {
1568  object *owner;
1569  rv_vector rv;
1570  int16_t x, y;
1571  mapstruct *map;
1572 
1573  if (!get_rangevector(part, pl, &rv, 1))
1574  return 0;
1575  if (rv.distance > 100)
1576  /* Too far */
1577  return 0;
1578  if (rv.distance_x != 0 && rv.distance_y != 0 && abs(rv.distance_x) != abs(rv.distance_y))
1579  /* Player must be on same horizontal, vertical or diagonal line. */
1580  return 0;
1581  dir = rv.direction;
1582 
1583  if (QUERY_FLAG(head, FLAG_FRIENDLY))
1584  owner = object_get_owner(head);
1585  else
1586  owner = NULL;
1587 
1588  /* The monster can possibly fire, let's see if the path is ok for an arrow. */
1589  x = part->x;
1590  y = part->y;
1591  map = part->map;
1592  while (x != pl->x || y != pl->y || map != pl->map) {
1593  x += freearr_x[dir];
1594  y += freearr_y[dir];
1595  map = get_map_from_coord(map, &x, &y);
1596  if (!map) {
1597  LOG(llevError, "monster_use_bow: no map but still path exists??\n");
1598  return 0;
1599  }
1601  return 0;
1602  if (owner && owner->x == x && owner->y == y && owner->map == map)
1603  /* Don't hit owner! */
1604  return 0;
1605  }
1606 
1607  /* Finally, path is clear, can fire. */
1608 
1609  if (QUERY_FLAG(head, FLAG_CONFUSED))
1610  dir = get_randomized_dir(dir);
1611 
1612  /* in server/player.c */
1613  return fire_bow(head, NULL, dir, 0, part->x, part->y);
1614 }
1615 
1624 static int monster_get_weapon_quality(const object *item) {
1625  int val;
1626  int i;
1627 
1628  val = item->stats.dam;
1629  val += item->magic*3;
1630  /* Monsters don't really get benefits from things like regen rates
1631  * from items. But the bonus for their stats are very important.
1632  */
1633  for (i = 0; i < NUM_STATS; i++)
1634  val += get_attr_value(&item->stats, i)*2;
1635  return val;
1636 }
1637 
1650 static int monster_check_good_weapon(object *who, object *item) {
1651  object *other_weap;
1652  int val;
1653 
1654  other_weap = object_find_by_type_applied(who, item->type);
1655  if (other_weap == NULL) /* No other weapons */
1656  return 1;
1657 
1658  /* Rather than go through and apply the new one, and see if it is
1659  * better, just do some simple checks
1660  * Put some multipliers for things that hvae several effects,
1661  * eg, magic affects both damage and wc, so it has more weight
1662  */
1663 
1665  return val > 0;
1666 }
1667 
1676 static int monster_get_armour_quality(const object *item) {
1677  int val;
1678 
1679  val = item->stats.ac;
1680  val += item->resist[ATNR_PHYSICAL]/5;
1681  val += item->magic*3;
1682  return val;
1683 }
1684 
1697 static int monster_check_good_armour(object *who, object *item) {
1698  object *other_armour;
1699  int val, i;
1700 
1701  other_armour = object_find_by_type_applied(who, item->type);
1702  if (other_armour == NULL) /* No other armour, use the new */
1703  return 1;
1704 
1706 
1707  /* for the other protections, do weigh them very much in the equation -
1708  * it is the armor protection which is most important, because there is
1709  * no good way to know what the player may attack the monster with.
1710  * So if the new item has better protection than the old, give that higher
1711  * value. If the reverse, then decrease the value of this item some.
1712  */
1713  for (i = 1; i < NROFATTACKS; i++) {
1714  if (item->resist[i] > other_armour->resist[i])
1715  val++;
1716  else if (item->resist[i] < other_armour->resist[i])
1717  val--;
1718  }
1719 
1720  /* Very few armours have stats, so not much need to worry about those. */
1721 
1722  return val > 0;
1723 }
1724 
1732 static void monster_check_apply(object *mon, object *item) {
1733  int flag = 0;
1734 
1735  if (item->type == SPELLBOOK
1736  && mon->arch != NULL
1737  && (QUERY_FLAG(&mon->arch->clone, FLAG_CAST_SPELL))) {
1739  return;
1740  }
1741 
1742  /* If for some reason, this item is already applied, no more work to do */
1744  return;
1745 
1746  /* Might be better not to do this - if the monster can fire a bow,
1747  * it is possible in his wanderings, he will find one to use. In
1748  * which case, it would be nice to have ammo for it.
1749  */
1750  if (QUERY_FLAG(mon, FLAG_USE_BOW) && item->type == ARROW) {
1751  /* Check for the right kind of bow */
1752  object *bow;
1753 
1754  bow = object_find_by_type_and_race(mon, BOW, item->race);
1755  if (bow != NULL) {
1757  LOG(llevMonster, "Found correct bow for arrows.\n");
1758  return; /* nothing more to do for arrows */
1759  }
1760  }
1761 
1762  if (item->type == TREASURE && mon->will_apply&WILL_APPLY_TREASURE)
1763  flag = 1;
1764  /* Eating food gets hp back */
1765  else if (item->type == FOOD && mon->will_apply&WILL_APPLY_FOOD)
1766  flag = 1;
1767  else if (item->type == SCROLL && QUERY_FLAG(mon, FLAG_USE_SCROLL)) {
1768  if (!item->inv)
1769  LOG(llevDebug, "Monster %d having scroll %d with empty inventory!\n", mon->count, item->count);
1770  else if (monster_should_cast_spell(item->inv))
1772  /* Don't use it right now */
1773  return;
1774  } else if (item->type == WEAPON)
1776  else if (IS_ARMOR(item) || IS_SHIELD(item))
1778  /* Should do something more, like make sure this is a better item */
1779  else if (item->type == RING)
1780  flag = 1;
1781  else if (item->type == WAND || item->type == ROD) {
1782  /* We never really 'ready' the wand/rod/horn, because that would mean the
1783  * weapon would get undone.
1784  */
1788  }
1789  return;
1790  } else if (item->type == BOW) {
1791  /* We never really 'ready' the bow, because that would mean the
1792  * weapon would get undone.
1793  */
1796  return;
1797  } else if (item->type == SKILL) {
1798  /*
1799  * skills are specials: monsters must have the 'FLAG_READY_SKILL' flag set,
1800  * else they can't use the skill...
1801  * Skills also don't need to get applied, so return now.
1802  */
1804  return;
1805  }
1806 
1807  /* if we don't match one of the above types, return now.
1808  * apply_can_apply_object() will say that we can apply things like flesh,
1809  * bolts, and whatever else, because it only checks against the
1810  * body_info locations.
1811  */
1812  if (!flag)
1813  return;
1814 
1815  /* Check to see if the monster can use this item. If not, no need
1816  * to do further processing. Note that apply_can_apply_object() already checks
1817  * for the CAN_USE flags.
1818  */
1820  return;
1821 
1822  /* should only be applying this item, not unapplying it.
1823  * also, ignore status of curse so they can take off old armour.
1824  * monsters have some advantages after all.
1825  */
1827  return;
1828 }
1829 
1849 static void monster_check_pickup(object *monster) {
1850  object *part;
1851 
1852  for (part = monster; part != NULL; part = part->more)
1853  FOR_BELOW_PREPARE(part, tmp) {
1854  /* Don't try to pick items that are in the process of being thrown.
1855  * It is fairly likely that an ally threw it past monster to hit player.
1856  * IDEA: Maybe have a dex save to catch player-thrown projectiles?
1857  *
1858  * Daniel Hawkins 2020-09-07
1859  */
1860  if (tmp->type != THROWN_OBJ && monster_can_pick(monster, tmp)) {
1861  uint32_t nrof;
1862 
1863  if (tmp->weight > 0) {
1864  int32_t weight_limit;
1865 
1866  weight_limit = get_weight_limit(monster->stats.Str);
1867  if (weight_limit >= monster->weight-monster->carrying)
1868  nrof = (weight_limit-monster->weight-monster->carrying)/tmp->weight;
1869  else
1870  nrof = 0;
1871  } else
1872  nrof = MAX(1, tmp->nrof);
1873  if (nrof >= 1) {
1874  object *tmp2;
1875 
1876  tmp2 = object_split(tmp, MIN(nrof, MAX(1, tmp->nrof)), NULL, 0);
1877  tmp2 = object_insert_in_ob(tmp2, monster);
1878  (void)monster_check_apply(monster, tmp2);
1879  }
1880  }
1881  } FOR_BELOW_FINISH();
1882 }
1883 
1893 static int monster_can_pick(object *monster, object *item) {
1894  int flag = 0;
1895  int i;
1896 
1897  if (!object_can_pick(monster, item))
1898  return 0;
1899 
1900  if (QUERY_FLAG(item, FLAG_UNPAID))
1901  return 0;
1902 
1903  if (monster->pick_up&64) /* All */
1904  flag = 1;
1905 
1906  else {
1907  if (IS_WEAPON(item))
1908  flag = (monster->pick_up&8) || QUERY_FLAG(monster, FLAG_USE_WEAPON);
1909  else if (IS_ARMOR(item))
1910  flag = (monster->pick_up&16) || QUERY_FLAG(monster, FLAG_USE_ARMOUR);
1911  else if (IS_SHIELD(item))
1912  flag = (monster->pick_up&16) || QUERY_FLAG(monster, FLAG_USE_SHIELD);
1913  else switch (item->type) {
1914  case MONEY:
1915  case GEM:
1916  flag = monster->pick_up&2;
1917  break;
1918 
1919  case FOOD:
1920  flag = monster->pick_up&4;
1921  break;
1922 
1923  case SKILL:
1924  flag = QUERY_FLAG(monster, FLAG_CAN_USE_SKILL);
1925  break;
1926 
1927  case RING:
1928  flag = QUERY_FLAG(monster, FLAG_USE_RING);
1929  break;
1930 
1931  case WAND:
1932  case ROD:
1933  flag = QUERY_FLAG(monster, FLAG_USE_RANGE);
1934  break;
1935 
1936  case SPELLBOOK:
1937  flag = (monster->arch != NULL && QUERY_FLAG(&monster->arch->clone, FLAG_CAST_SPELL));
1938  break;
1939 
1940  case SCROLL:
1941  flag = QUERY_FLAG(monster, FLAG_USE_SCROLL);
1942  break;
1943 
1944  case BOW:
1945  case ARROW:
1946  flag = QUERY_FLAG(monster, FLAG_USE_BOW);
1947  break;
1948  }
1949  if (!flag && QUERY_FLAG(item, FLAG_IS_THROWN) && object_find_by_type_subtype(monster, SKILL, SK_THROWING) != NULL)
1950  flag = (monster->pick_up&8) || QUERY_FLAG(monster, FLAG_USE_WEAPON);
1951  /* Simplistic check - if the monster has a location to equip it, he will
1952  * pick it up. Note that this doesn't handle cases where an item may
1953  * use several locations.
1954  */
1955  for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
1956  if (monster->body_info[i] && item->body_info[i]) {
1957  flag = 1;
1958  break;
1959  }
1960  }
1961  }
1962 
1963  if (((!(monster->pick_up&32)) && flag) || ((monster->pick_up&32) && (!flag)))
1964  return 1;
1965  return 0;
1966 }
1967 
1974 static void monster_apply_below(object *monster) {
1975  FOR_BELOW_PREPARE(monster, tmp) {
1976  switch (tmp->type) {
1977  case CF_HANDLE:
1978  case TRIGGER:
1979  if (monster->will_apply&WILL_APPLY_HANDLE)
1980  apply_manual(monster, tmp, 0);
1981  break;
1982 
1983  case TREASURE:
1984  if (monster->will_apply&WILL_APPLY_TREASURE)
1985  apply_manual(monster, tmp, 0);
1986  break;
1987  }
1989  break;
1990  } FOR_BELOW_FINISH();
1991 }
1992 
1997 void monster_check_apply_all(object *monster) {
1998  if (!monster->head) {
1999  fix_object(monster); // Needed to correctly fill various body fields.
2000  }
2001  FOR_INV_PREPARE(monster, inv)
2002  monster_check_apply(monster, inv);
2003  FOR_INV_FINISH();
2004 }
2005 
2010 void monster_npc_call_help(object *op) {
2011  const char *value;
2012  int help_radius = 3;
2013 
2014  value = object_get_value(op, "help_radius");
2015  if ( value ) {
2016  int override_help_radius;
2017 
2018  override_help_radius = strtol(value, NULL, 10);
2019  if (override_help_radius >= 0 && override_help_radius < 30)
2020  help_radius = override_help_radius;
2021  else
2022  LOG(llevDebug, "monster_npc_call_help: invalid help_radius %d\n", override_help_radius);
2023  }
2024 
2025  for (int x = -help_radius; x <= help_radius; x++)
2026  for (int y = -help_radius; y <= help_radius; y++) {
2027  mapstruct *m = op->map;
2028  int16_t sx = op->x+x;
2029  int16_t sy = op->y+y;
2030  int mflags = get_map_flags(m, &m, sx, sy, &sx, &sy);
2031  /* If nothing alive on this space, no need to search the space. */
2032  if ((mflags&P_OUT_OF_MAP) || !(mflags&P_IS_ALIVE))
2033  continue;
2034 
2035  FOR_MAP_PREPARE(m, sx, sy, npc)
2037  object_set_enemy(npc, op->enemy);
2039  }
2040  FOR_MAP_FINISH();
2041  }
2042 }
2043 
2052 static int monster_dist_att(int dir, object *enemy, object *part, rv_vector *rv) {
2053  if (monster_can_hit(part, enemy, rv))
2054  return dir;
2055  if (rv->distance < 10)
2056  return absdir(dir+4);
2057  else if (rv->distance > 18)
2058  return dir;
2059  return 0;
2060 }
2061 
2071 static int monster_run_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv) {
2072  if ((monster_can_hit(part, enemy, rv) && ob->move_status < 20) || ob->move_status < 20) {
2073  ob->move_status++;
2074  return (dir);
2075  } else if (ob->move_status > 20)
2076  ob->move_status = 0;
2077  return absdir(dir+4);
2078 }
2079 
2086 static int monster_hitrun_att(int dir, object *ob) {
2087  if (ob->move_status++ < 25)
2088  return dir;
2089  else if (ob->move_status < 50)
2090  return absdir(dir+4);
2091  ob->move_status = 0;
2092  return absdir(dir+4);
2093 }
2094 
2104 static int monster_wait_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv) {
2105  int inrange = monster_can_hit(part, enemy, rv);
2106 
2107  if (ob->move_status || inrange)
2108  ob->move_status++;
2109 
2110  if (ob->move_status == 0)
2111  return 0;
2112  else if (ob->move_status < 10)
2113  return dir;
2114  else if (ob->move_status < 15)
2115  return absdir(dir+4);
2116  ob->move_status = 0;
2117  return 0;
2118 }
2119 
2129 static int monster_disthit_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv) {
2130  /* The logic below here looked plain wrong before. Basically, what should
2131  * happen is that if the creatures hp percentage falls below run_away,
2132  * the creature should run away (dir+4)
2133  * I think its wrong for a creature to have a zero maxhp value, but
2134  * at least one map has this set, and whatever the map contains, the
2135  * server should try to be resilant enough to avoid the problem
2136  */
2137  if (ob->stats.maxhp && (ob->stats.hp*100)/ob->stats.maxhp < ob->run_away)
2138  return absdir(dir+4);
2139  return monster_dist_att(dir, enemy, part, rv);
2140 }
2141 
2148 static int monster_wait_att2(int dir, rv_vector *rv) {
2149  if (rv->distance < 9)
2150  return absdir(dir+4);
2151  return 0;
2152 }
2153 
2158 static void monster_circ1_move(object *ob) {
2159  static const int circle [12] = { 3, 3, 4, 5, 5, 6, 7, 7, 8, 1, 1, 2 };
2160 
2161  if (++ob->move_status > 11)
2162  ob->move_status = 0;
2163  if (!(move_object(ob, circle[ob->move_status])))
2164  (void)move_object(ob, RANDOM()%8+1);
2165 }
2166 
2171 static void monster_circ2_move(object *ob) {
2172  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 };
2173 
2174  if (++ob->move_status > 19)
2175  ob->move_status = 0;
2176  if (!(move_object(ob, circle[ob->move_status])))
2177  (void)move_object(ob, RANDOM()%8+1);
2178 }
2179 
2184 static void monster_pace_movev(object *ob) {
2185  if (ob->move_status++ > 6)
2186  ob->move_status = 0;
2187  if (ob->move_status < 4)
2188  (void)move_object(ob, 5);
2189  else
2190  (void)move_object(ob, 1);
2191 }
2192 
2197 static void monster_pace_moveh(object *ob) {
2198  if (ob->move_status++ > 6)
2199  ob->move_status = 0;
2200  if (ob->move_status < 4)
2201  (void)move_object(ob, 3);
2202  else
2203  (void)move_object(ob, 7);
2204 }
2205 
2210 static void monster_pace2_movev(object *ob) {
2211  if (ob->move_status++ > 16)
2212  ob->move_status = 0;
2213  if (ob->move_status < 6)
2214  (void)move_object(ob, 5);
2215  else if (ob->move_status < 8)
2216  return;
2217  else if (ob->move_status < 13)
2218  (void)move_object(ob, 1);
2219 }
2220 
2225 static void monster_pace2_moveh(object *ob) {
2226  if (ob->move_status++ > 16)
2227  ob->move_status = 0;
2228  if (ob->move_status < 6)
2229  (void)move_object(ob, 3);
2230  else if (ob->move_status < 8)
2231  return;
2232  else if (ob->move_status < 13)
2233  (void)move_object(ob, 7);
2234 }
2235 
2240 static void monster_rand_move(object *ob) {
2241  int i;
2242 
2243  if (ob->move_status < 1
2244  || ob->move_status > 8
2245  || !(move_object(ob, ob->move_status || !(RANDOM()%9))))
2246  for (i = 0; i < 5; i++) {
2247  ob->move_status = RANDOM()%8+1;
2248  if (move_object(ob, ob->move_status))
2249  return;
2250  }
2251 }
2252 
2260 void monster_check_earthwalls(object *op, mapstruct *m, int x, int y) {
2261  FOR_MAP_PREPARE(m, x, y, tmp)
2262  if (tmp->type == EARTHWALL) {
2263  hit_player(tmp, op->stats.dam, op, AT_PHYSICAL, 1);
2264  return;
2265  }
2266  FOR_MAP_FINISH();
2267 }
2268 
2276 void monster_check_doors(object *op, mapstruct *m, int x, int y) {
2277  FOR_MAP_PREPARE(m, x, y, tmp)
2278  if (tmp->type == DOOR) {
2279  hit_player(tmp, op->stats.dam, op, AT_PHYSICAL, 1);
2280  return;
2281  }
2282  FOR_MAP_FINISH();
2283 }
2284 
2290 void monster_do_say(const mapstruct *map, const char *message) {
2292  message);
2293 }
2294 
2301 static StringBuffer *monster_format_say(const object* npc, const char *message) {
2302  char name[MAX_BUF];
2303  StringBuffer *buf;
2304 
2305  query_name(npc, name, sizeof(name));
2306  buf = stringbuffer_new();
2307  stringbuffer_append_printf(buf, "%s says: %s", name, message);
2308  return buf;
2309 }
2310 
2317  switch (rt) {
2318  case rt_say:
2319  return "say";
2320  case rt_reply:
2321  return "reply";
2322  case rt_question:
2323  return "ask";
2324  }
2325  assert(0);
2326  return NULL;
2327 }
2328 
2334 static const char *get_reply_text_other(reply_type rt) {
2335  switch (rt) {
2336  case rt_say:
2337  return "says";
2338  case rt_reply:
2339  return "replies";
2340  case rt_question:
2341  return "asks";
2342  }
2343  assert(0);
2344  return NULL;
2345 }
2346 
2372 void monster_communicate(object *op, const char *txt) {
2373  int i, mflags;
2374  int16_t x, y;
2375  mapstruct *mp, *orig_map = op->map;
2376  char own[MAX_BUF], others[MAX_BUF];
2377  talk_info info;
2378 
2379  info.text = txt;
2380  info.message = NULL;
2381  info.replies_count = 0;
2382  info.who = op;
2383  info.npc_msg_count = 0;
2384 
2385  /* Note that this loop looks pretty inefficient to me - we look and try to talk
2386  * to every object within 2 spaces. It would seem that if we trim this down to
2387  * only try to talk to objects with npc->msg set, things would be a lot more efficient,
2388  * but I'm not sure if there are any objects out there that don't have a message and instead
2389  * rely sorely on events - MSW 2009-04-14
2390  */
2391  for (i = 0; i <= SIZEOFFREE2; i++) {
2392  mp = op->map;
2393  x = op->x+freearr_x[i];
2394  y = op->y+freearr_y[i];
2395 
2396  mflags = get_map_flags(mp, &mp, x, y, &x, &y);
2397  if (mflags&P_OUT_OF_MAP)
2398  continue;
2399 
2400  FOR_MAP_PREPARE(mp, x, y, npc) {
2401  monster_talk_to_npc(npc, &info);
2402  if (orig_map != op->map) {
2403  LOG(llevDebug, "Warning: Forced to swap out very recent map\n");
2404  return;
2405  }
2406  } FOR_MAP_FINISH();
2407  }
2408 
2409  /* First, what the player says. */
2410  if (info.message != NULL) {
2411  snprintf(own, sizeof(own), "You %s: %s", get_reply_text_own(info.message_type), info.message);
2412  snprintf(others, sizeof(others), "%s %s: %s", op->name, get_reply_text_other(info.message_type), info.message);
2413  free_string(info.message);
2414  } else {
2415  snprintf(own, sizeof(own), "You say: %s", txt);
2416  snprintf(others, sizeof(others), "%s says: %s", op->name, txt);
2417  }
2420 
2421  /* Then NPCs can actually talk. */
2422  for (i = 0; i < info.npc_msg_count; i++) {
2423  monster_do_say(orig_map, info.npc_msgs[i]);
2424  free_string(info.npc_msgs[i]);
2425  }
2426 
2427  /* Finally, the replies the player can use. */
2428  if (info.replies_count > 0) {
2430  for (i = 0; i < info.replies_count; i++) {
2432  free_string(info.replies_words[i]);
2433  free_string(info.replies[i]);
2434  }
2435  }
2436 }
2437 
2446 static int monster_do_talk_npc(object *npc, talk_info *info) {
2449 
2450  if (!get_dialog_message(npc, info->text, &message, &reply))
2451  return 0;
2452 
2453  if (reply) {
2454  info->message = add_string(reply->message);
2455  info->message_type = reply->type;
2456  }
2457 
2458  if (message->identifies) {
2459  identify(npc);
2460  }
2461 
2462  if (npc->type == MAGIC_EAR) {
2464  use_trigger(npc);
2465  } else {
2466  char value[2];
2467 
2468  if (info->npc_msg_count < MAX_NPC) {
2470  info->npc_msg_count++;
2471  }
2472 
2473  /* mark that the npc was talked to, so it won't move randomly later on */
2474  value[0] = '3' + rand() % 6;
2475  value[1] = '\0';
2476  object_set_value(npc, "talked_to", value, 1);
2477 
2478  reply = message->replies;
2479  while (reply && info->replies_count < MAX_REPLIES) {
2480  info->replies[info->replies_count] = add_string(reply->message);
2481  info->replies_words[info->replies_count] = add_string(reply->reply);
2482  info->replies_count++;
2483  reply = reply->next;
2484  }
2485  }
2486 
2487  return 1;
2488 }
2489 
2495 void monster_npc_say(object *npc, const char *cp) {
2496  char *message;
2498 
2500  monster_do_say(npc->map, message);
2501  free(message);
2502 }
2503 
2512 static int monster_talk_to_npc(object *npc, talk_info *info) {
2513 
2514  if (events_execute_object_say(npc, info) != 0)
2515  return 0;
2516 
2517  /* Here we let the objects inside inventories hear and answer, too. */
2518  /* This allows the existence of "intelligent" weapons you can discuss with */
2519  FOR_INV_PREPARE(npc, cobj)
2520  if (events_execute_object_say(cobj, info) != 0)
2521  return 0;
2522  FOR_INV_FINISH();
2523  if (info->who == npc)
2524  return 0;
2525  return monster_do_talk_npc(npc, info);
2526 }
2527 
2540 object *monster_find_throw_ob(object *op) {
2541  /* New throw code: look through the inventory. Grap the first legal is_thrown
2542  * marked item and throw it to the enemy.
2543  */
2544 
2545  FOR_INV_PREPARE(op, tmp) {
2546  /* Can't throw invisible objects or items that are applied */
2547  if (!tmp->invisible && !QUERY_FLAG(tmp, FLAG_APPLIED) && QUERY_FLAG(tmp, FLAG_IS_THROWN)) {
2548 #ifdef DEBUG_THROW
2549  char what[MAX_BUF];
2550 
2551  query_name(tmp, what, MAX_BUF);
2552  LOG(llevDebug, "%s chooses to throw: %s (%d)\n", op->name, what, tmp->count);
2553 #endif
2554  return tmp;
2555  }
2556  } FOR_INV_FINISH();
2557 
2558 #ifdef DEBUG_THROW
2559  LOG(llevDebug, "%s chooses to throw nothing\n", op->name);
2560 #endif
2561  return NULL;
2562 }
2563 
2579 int monster_can_detect_enemy(object *op, object *enemy, rv_vector *rv) {
2580  int radius = MIN_MON_RADIUS, hide_discovery;
2581 
2582  /* null detection for any of these condtions always */
2583  if (!op || !enemy || !op->map || !enemy->map)
2584  return 0;
2585 
2586  /* If the monster (op) has no way to get to the enemy, do nothing */
2587  if (!get_rangevector(op, enemy, rv, 0))
2588  return 0;
2589 
2590  /* Monsters always ignore the DM */
2591  if (op->type != PLAYER && QUERY_FLAG(enemy, FLAG_WIZ))
2592  return 0;
2593 
2594  /* simple check. Should probably put some range checks in here. */
2595  if (monster_can_see_enemy(op, enemy))
2596  return 1;
2597 
2598  /* The rest of this is for monsters. Players are on their own for
2599  * finding enemies!
2600  */
2601  if (op->type == PLAYER)
2602  return 0;
2603 
2604  /* Quality invisible? Bah, we wont see them w/o SEE_INVISIBLE
2605  * flag (which was already checked) in can_see_enmy (). Lets get out of here
2606  */
2607  if (enemy->invisible && (!enemy->contr || (!enemy->contr->tmp_invis && !enemy->contr->hidden)))
2608  return 0;
2609 
2610  /* use this for invis also */
2611  hide_discovery = op->stats.Int/5;
2612 
2613  /* Determine Detection radii */
2614  if (!enemy->hide) /* to detect non-hidden (eg dark/invis enemy) */
2615  radius = MAX(op->stats.Wis/5+1, MIN_MON_RADIUS);
2616  else { /* a level/INT/Dex adjustment for hiding */
2617  object *sk_hide;
2618  int bonus = (op->level/2)+(op->stats.Int/5);
2619 
2620  if (enemy->type == PLAYER) {
2621  sk_hide = find_skill_by_number(enemy, SK_HIDING);
2622  if (sk_hide != NULL)
2623  bonus -= sk_hide->level;
2624  else {
2625  LOG(llevError, "monster_can_detect_enemy() got hidden player w/o hiding skill!\n");
2626  make_visible(enemy);
2627  radius = MAX(radius, MIN_MON_RADIUS);
2628  }
2629  } else /* enemy is not a player */
2630  bonus -= enemy->level;
2631 
2632  radius += bonus/5;
2633  hide_discovery += bonus*5;
2634  } /* else creature has modifiers for hiding */
2635 
2636  /* Radii stealth adjustment. Only if you are stealthy
2637  * will you be able to sneak up closer to creatures */
2638  if (QUERY_FLAG(enemy, FLAG_STEALTH))
2639  radius = radius/2, hide_discovery = hide_discovery/3;
2640 
2641  /* Radii adjustment for enemy standing in the dark */
2642  if (op->map->darkness > 0 && !monster_stand_in_light(enemy)) {
2643  /* on dark maps body heat can help indicate location with infravision
2644  * undead don't have body heat, so no benefit detecting them.
2645  */
2646  if (QUERY_FLAG(op, FLAG_SEE_IN_DARK) && !is_true_undead(enemy))
2647  radius += op->map->darkness/2;
2648  else
2649  radius -= op->map->darkness/2;
2650 
2651  /* op next to a monster (and not in complete darkness)
2652  * the monster should have a chance to see you.
2653  */
2654  if (radius < MIN_MON_RADIUS && op->map->darkness < 5 && rv->distance <= 1)
2655  radius = MIN_MON_RADIUS;
2656  } /* if on dark map */
2657 
2658  /* Lets not worry about monsters that have incredible detection
2659  * radii, we only need to worry here about things the player can
2660  * (potentially) see. This is 13, as that is the maximum size the player
2661  * may have for their map - in that way, creatures at the edge will
2662  * do something. Note that the distance field in the
2663  * vector is real distance, so in theory this should be 18 to
2664  * find that.
2665  */
2666  if (radius > 13)
2667  radius = 13;
2668 
2669  /* Enemy in range! Now test for detection */
2670  if ((int)rv->distance <= radius) {
2671  /* ah, we are within range, detected? take cases */
2672  if (!enemy->invisible) /* enemy in dark squares... are seen! */
2673  return 1;
2674 
2675  /* hidden or low-quality invisible */
2676  if (enemy->hide && rv->distance <= 1 && RANDOM()%100 <= (unsigned int)hide_discovery) {
2677  make_visible(enemy);
2678  /* inform players of new status */
2679  if (enemy->type == PLAYER && player_can_view(enemy, op))
2681  "You are discovered by %s!",
2682  op->name);
2683  return 1; /* detected enemy */
2684  } else if (enemy->invisible) {
2685  /* Change this around - instead of negating the invisible, just
2686  * return true so that the mosnter that managed to detect you can
2687  * do something to you. Decreasing the duration of invisible
2688  * doesn't make a lot of sense IMO, as a bunch of stupid creatures
2689  * can then basically negate the spell. The spell isn't negated -
2690  * they just know where you are!
2691  */
2692  if (RANDOM()%50 <= (unsigned int)hide_discovery) {
2693  if (enemy->type == PLAYER) {
2694  char name[MAX_BUF];
2695 
2698  "You see %s noticing your position.",
2699  name);
2700  }
2701  return 1;
2702  }
2703  }
2704  } /* within range */
2705 
2706  /* Wasn't detected above, so still hidden */
2707  return 0;
2708 }
2709 
2720  int16_t nx, ny;
2721  mapstruct *m;
2722 
2723  if (!op)
2724  return 0;
2725  if (op->glow_radius > 0)
2726  return 1;
2727 
2728  if (op->map) {
2729  int x, y, x1, y1;
2730 
2731  /* Check the spaces with the max light radius to see if any of them
2732  * have lights, and if any of them light the player enough, then return 1.
2733  */
2734  for (x = op->x-MAX_LIGHT_RADII; x <= op->x+MAX_LIGHT_RADII; x++) {
2735  for (y = op->y-MAX_LIGHT_RADII; y <= op->y+MAX_LIGHT_RADII; y++) {
2736  m = op->map;
2737  nx = x;
2738  ny = y;
2739 
2740  if (get_map_flags(m, &m, nx, ny, &nx, &ny)&P_OUT_OF_MAP)
2741  continue;
2742 
2743  x1 = abs(x-op->x)*abs(x-op->x);
2744  y1 = abs(y-op->y)*abs(y-op->y);
2745  if (isqrt(x1+y1) < GET_MAP_LIGHT(m, nx, ny))
2746  return 1;
2747  }
2748  }
2749  }
2750  return 0;
2751 }
2752 
2762 int monster_can_see_enemy(object *op, object *enemy) {
2763  object *looker = HEAD(op);
2764 
2765  /* safety */
2766  if (!looker || !enemy || !QUERY_FLAG(looker, FLAG_ALIVE))
2767  return 0;
2768 
2769  /* we dont give a full treatment of xrays here (shorter range than normal,
2770  * see through walls). Should we change the code elsewhere to make you
2771  * blind even if you can xray?
2772  */
2773  if (QUERY_FLAG(looker, FLAG_BLIND) && !QUERY_FLAG(looker, FLAG_XRAYS))
2774  return 0;
2775 
2776  /* checking for invisible things */
2777  if (enemy->invisible) {
2778  /* HIDDEN ENEMY. by definition, you can't see hidden stuff!
2779  * However, if you carry any source of light, then the hidden
2780  * creature is seeable (and stupid) */
2781  if (has_carried_lights(enemy)) {
2782  if (enemy->hide) {
2783  make_visible(enemy);
2785  "Your light reveals your hiding spot!");
2786  }
2787  return 1;
2788  } else if (enemy->hide)
2789  return 0;
2790 
2791  /* Invisible enemy. Break apart the check for invis undead/invis looker
2792  * into more simple checks - the QUERY_FLAG doesn't return 1/0 values,
2793  * and making it a conditional makes the code pretty ugly.
2794  */
2795  if (!QUERY_FLAG(looker, FLAG_SEE_INVISIBLE)) {
2796  if (makes_invisible_to(enemy, looker))
2797  return 0;
2798  }
2799  } else if (looker->type == PLAYER) /* for players, a (possible) shortcut */
2800  if (player_can_view(looker, enemy))
2801  return 1;
2802 
2803  /* ENEMY IN DARK MAP. Without infravision, the enemy is not seen
2804  * unless they carry a light or stand in light. Darkness doesnt
2805  * inhibit the undead per se (but we should give their archs
2806  * CAN_SEE_IN_DARK, this is just a safety
2807  * we care about the enemy maps status, not the looker.
2808  * only relevant for tiled maps, but it is possible that the
2809  * enemy is on a bright map and the looker on a dark - in that
2810  * case, the looker can still see the enemy
2811  */
2812  if (enemy->map->darkness > 0
2813  && !monster_stand_in_light(enemy)
2814  && (!QUERY_FLAG(looker, FLAG_SEE_IN_DARK) || !is_true_undead(looker) || !QUERY_FLAG(looker, FLAG_XRAYS)))
2815  return 0;
2816 
2817  return 1;
2818 }
object_value_set
bool object_value_set(const object *op, const char *const key)
Definition: object.cpp:4369
mapdef::height
uint16_t height
Definition: map.h:340
FLAG_USE_BOW
#define FLAG_USE_BOW
Definition: define.h:293
GET_MAP_OB
#define GET_MAP_OB(M, X, Y)
Definition: map.h:173
do_skill
int do_skill(object *op, object *part, object *skill, int dir, const char *string)
Definition: skill_util.cpp:422
TRIGGER
@ TRIGGER
Definition: object.h:132
PLAYER
@ PLAYER
Definition: object.h:110
obj::attack_movement
uint16_t attack_movement
Definition: object.h:399
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:631
monster_pace2_movev
static void monster_pace2_movev(object *ob)
Definition: monster.cpp:2210
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:4294
SP_BOLT
#define SP_BOLT
Definition: spells.h:78
CF_HANDLE
@ CF_HANDLE
Definition: object.h:211
liv::dam
int16_t dam
Definition: living.h:46
talk_info::replies
sstring replies[MAX_REPLIES]
Definition: dialog.h:59
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Definition: define.h:730
remove_friendly_object
void remove_friendly_object(object *op)
Definition: friend.cpp:54
object_find_by_type_applied
object * object_find_by_type_applied(const object *who, int type)
Definition: object.cpp:4076
NUM_BODY_LOCATIONS
#define NUM_BODY_LOCATIONS
Definition: object.h:13
obj::face
const Face * face
Definition: object.h:339
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:121
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:223
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:58
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
talk_info::npc_msg_count
int npc_msg_count
Definition: dialog.h:60
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:1997
FLAG_GENERATOR
#define FLAG_GENERATOR
Definition: define.h:248
diamondslots.x
x
Definition: diamondslots.py:15
obj::count
tag_t count
Definition: object.h:305
RUNATT
#define RUNATT
Definition: define.h:493
obj::map
struct mapdef * map
Definition: object.h:303
MSG_TYPE_SKILL
#define MSG_TYPE_SKILL
Definition: newclient.h:407
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
PACEV2
#define PACEV2
Definition: define.h:526
pl::peaceful
uint32_t peaceful
Definition: player.h:146
monster_disthit_att
static int monster_disthit_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv)
Definition: monster.cpp:2129
pets_should_arena_attack
int pets_should_arena_attack(object *pet, object *owner, object *target)
Definition: pets.cpp:1086
liv::wc
int8_t wc
Definition: living.h:37
path_data
Definition: monster.cpp:415
make_visible
void make_visible(object *op)
Definition: player.cpp:3913
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:52
liv::Str
int8_t Str
Definition: living.h:36
FLAG_SEE_IN_DARK
#define FLAG_SEE_IN_DARK
Definition: define.h:337
AT_PHYSICAL
#define AT_PHYSICAL
Definition: attack.h:76
cast_spell
int cast_spell(object *op, object *caster, int dir, object *spell_ob, char *stringarg)
Definition: spell_util.cpp:1420
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Definition: stringbuffer.cpp:57
absdir
int absdir(int d)
Definition: object.cpp:3707
obj::attacked_by_count
tag_t attacked_by_count
Definition: object.h:391
FOR_BELOW_PREPARE
#define FOR_BELOW_PREPARE(op_, it_)
Definition: define.h:704
object_set_enemy
void object_set_enemy(object *op, object *enemy)
Definition: object.cpp:915
GEM
@ GEM
Definition: object.h:170
pl
Definition: player.h:105
monster_check_good_weapon
static int monster_check_good_weapon(object *who, object *item)
Definition: monster.cpp:1650
HITRUN
#define HITRUN
Definition: define.h:494
monster_check_enemy
object * monster_check_enemy(object *npc, rv_vector *rv)
Definition: monster.cpp:72
WEAPON
@ WEAPON
Definition: object.h:122
obj::invisible
int16_t invisible
Definition: object.h:368
monster_run_att
static int monster_run_att(int dir, object *ob, object *enemy, object *part, rv_vector *rv)
Definition: monster.cpp:2071
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:2276
SP_CONE
#define SP_CONE
Definition: spells.h:81
commongive.inv
inv
Definition: commongive.py:28
FLAG_SEE_INVISIBLE
#define FLAG_SEE_INVISIBLE
Definition: define.h:253
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:1849
mon
object * mon
Definition: comet_perf.cpp:75
MIN
#define MIN(x, y)
Definition: compat.h:21
TREASURE
@ TREASURE
Definition: object.h:113
talk_info::who
struct obj * who
Definition: dialog.h:53
SKILL
@ SKILL
Definition: object.h:146
monster_check_good_armour
static int monster_check_good_armour(object *who, object *item)
Definition: monster.cpp:1697
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:244
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:563
ATNR_PHYSICAL
#define ATNR_PHYSICAL
Definition: attack.h:49
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
obj::body_info
int8_t body_info[NUM_BODY_LOCATIONS]
Definition: object.h:380
skills.h
rv_vector::part
object * part
Definition: map.h:378
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
object_get_value
const char * object_get_value(const object *op, const char *const key)
Definition: object.cpp:4339
P_IS_ALIVE
#define P_IS_ALIVE
Definition: map.h:238
FLAG_APPLIED
#define FLAG_APPLIED
Definition: define.h:235
FLAG_STEALTH
#define FLAG_STEALTH
Definition: define.h:312
FLAG_BLIND
#define FLAG_BLIND
Definition: define.h:336
buf
StringBuffer * buf
Definition: readable.cpp:1611
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:2851
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:520
monster_rand_move
static void monster_rand_move(object *ob)
Definition: monster.cpp:2240
talk_info::message
sstring message
Definition: dialog.h:55
FOR_BELOW_FINISH
#define FOR_BELOW_FINISH()
Definition: define.h:711
talk_info::replies_count
int replies_count
Definition: dialog.h:57
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:376
FOR_OB_AND_ABOVE_PREPARE
#define FOR_OB_AND_ABOVE_PREPARE(op_)
Definition: define.h:739
obj::chosen_skill
struct obj * chosen_skill
Definition: object.h:394
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:2148
object_find_by_type_and_race
object * object_find_by_type_and_race(const object *who, int type, const char *race)
Definition: object.cpp:4126
m
static event_registration m
Definition: citylife.cpp:425
obj::attacked_by
struct obj * attacked_by
Definition: object.h:390
rv_vector::distance_x
int distance_x
Definition: map.h:375
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
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
obj::name
sstring name
Definition: object.h:317
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:2104
monster_get_armour_quality
static int monster_get_armour_quality(const object *item)
Definition: monster.cpp:1676
pl::tmp_invis
uint32_t tmp_invis
Definition: player.h:140
query_name
void query_name(const object *op, char *buf, size_t size)
Definition: item.cpp:585
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:3815
monster_get_weapon_quality
static int monster_get_weapon_quality(const object *item)
Definition: monster.cpp:1624
MOVE_WALK
#define MOVE_WALK
Definition: define.h:392
stringbuffer_finish_shared
sstring stringbuffer_finish_shared(StringBuffer *sb)
Definition: stringbuffer.cpp:85
monster_can_see_enemy
int monster_can_see_enemy(object *op, object *enemy)
Definition: monster.cpp:2762
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:1974
HEAD
#define HEAD(op)
Definition: object.h:596
ROD
@ ROD
Definition: object.h:112
obj::hide
uint8_t hide
Definition: object.h:395
NDI_DELAYED
#define NDI_DELAYED
Definition: newclient.h:269
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
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:2171
isqrt
int isqrt(int n)
Definition: utils.cpp:569
path_data::x
int16_t x
Definition: monster.cpp:416
has_carried_lights
int has_carried_lights(const object *op)
Definition: los.cpp:315
MIN_MON_RADIUS
#define MIN_MON_RADIUS
Definition: monster.cpp:56
struct_dialog_reply
Definition: dialog.h:18
monster_pace2_moveh
static void monster_pace2_moveh(object *ob)
Definition: monster.cpp:2225
obj::carrying
int32_t carrying
Definition: object.h:375
MAX_NPC
#define MAX_NPC
Definition: dialog.h:47
CIRCLE2
#define CIRCLE2
Definition: define.h:513
obj::x
int16_t x
Definition: object.h:333
monster_pace_moveh
static void monster_pace_moveh(object *ob)
Definition: monster.cpp:2197
SP_SMITE
#define SP_SMITE
Definition: spells.h:84
FLAG_PARALYZED
#define FLAG_PARALYZED
Definition: define.h:371
FLAG_USE_SHIELD
#define FLAG_USE_SHIELD
Definition: define.h:237
mapdef::darkness
uint8_t darkness
Definition: map.h:339
rt_say
@ rt_say
Definition: dialog.h:10
GET_MAP_MOVE_BLOCK
#define GET_MAP_MOVE_BLOCK(M, X, Y)
Definition: map.h:193
FOR_INV_FINISH
#define FOR_INV_FINISH()
Definition: define.h:677
is_enemy
static int is_enemy(object *who, object *owner)
Definition: monster.cpp:142
GOLEM
@ GOLEM
Definition: object.h:148
apply_can_apply_object
int apply_can_apply_object(const object *who, const object *op)
Definition: apply.cpp:1016
sstring
const typedef char * sstring
Definition: global.h:43
FLAG_UNAGGRESSIVE
#define FLAG_UNAGGRESSIVE
Definition: define.h:272
monster_choose_random_spell
static object * monster_choose_random_spell(object *monster)
Definition: monster.cpp:1226
FLAG_USE_WEAPON
#define FLAG_USE_WEAPON
Definition: define.h:296
sproto.h
ARROW
@ ARROW
Definition: object.h:120
IS_SHIELD
#define IS_SHIELD(op)
Definition: define.h:170
GET_MAP_LIGHT
#define GET_MAP_LIGHT(M, X, Y)
Definition: map.h:166
get_map_from_coord
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
Definition: map.cpp:2393
FLAG_CAN_USE_SKILL
#define FLAG_CAN_USE_SKILL
Definition: define.h:321
rt_reply
@ rt_reply
Definition: dialog.h:11
PACEV
#define PACEV
Definition: define.h:524
monster_can_pick
static int monster_can_pick(object *monster, object *item)
Definition: monster.cpp:1893
obj::enemy
struct obj * enemy
Definition: object.h:389
mapdef
Definition: map.h:317
SP_level_spellpoint_cost
int16_t SP_level_spellpoint_cost(object *caster, object *spell, int flags)
Definition: spell_util.cpp:235
monster_format_say
static StringBuffer * monster_format_say(const object *npc, const char *message)
Definition: monster.cpp:2301
monster_compute_path
int monster_compute_path(object *source, object *target, int default_dir)
Definition: monster.cpp:465
monster_find_throw_ob
object * monster_find_throw_ob(object *op)
Definition: monster.cpp:2540
RING
@ RING
Definition: object.h:188
liv::Int
int8_t Int
Definition: living.h:36
obj::animation
const Animations * animation
Definition: object.h:424
ob_blocked
int ob_blocked(const object *ob, mapstruct *m, int16_t x, int16_t y)
Definition: map.cpp:488
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:580
monster_hitrun_att
static int monster_hitrun_att(int dir, object *ob)
Definition: monster.cpp:2086
monster_npc_call_help
void monster_npc_call_help(object *op)
Definition: monster.cpp:2010
SIZEOFFREE
#define SIZEOFFREE
Definition: define.h:155
P_OUT_OF_MAP
#define P_OUT_OF_MAP
Definition: map.h:250
MAX_BUF
#define MAX_BUF
Definition: define.h:35
monster_use_range
static int monster_use_range(object *head, object *part, object *pl, int dir)
Definition: monster.cpp:1491
obj::spellitem
struct obj * spellitem
Definition: object.h:402
MSG_TYPE_DIALOG
#define MSG_TYPE_DIALOG
Definition: newclient.h:400
minheap_remove
void * minheap_remove(MinHeap *heap)
Definition: minheap.cpp:209
IS_WEAPON
#define IS_WEAPON(op)
Definition: define.h:163
get_weight_limit
uint32_t get_weight_limit(int stat)
Definition: living.cpp:2360
use_trigger
void use_trigger(object *op)
Definition: button.cpp:254
talk_info::text
const char * text
Definition: dialog.h:54
free_string
void free_string(sstring str)
Definition: shstr.cpp:280
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
obj::y
int16_t y
Definition: object.h:333
SP_INVISIBLE
#define SP_INVISIBLE
Definition: spells.h:93
OUT_OF_REAL_MAP
#define OUT_OF_REAL_MAP(M, X, Y)
Definition: map.h:218
MAGIC_EAR
@ MAGIC_EAR
Definition: object.h:134
get_search_arr
void get_search_arr(int *search_arr)
Definition: object.cpp:3635
obj::arch
struct archt * arch
Definition: object.h:420
MAX_KNOWN_SPELLS
#define MAX_KNOWN_SPELLS
Definition: monster.cpp:1209
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:9
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
obj::type
uint8_t type
Definition: object.h:346
talk_info::message_type
reply_type message_type
Definition: dialog.h:56
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:262
monster_circ1_move
static void monster_circ1_move(object *ob)
Definition: monster.cpp:2158
FLAG_FRIENDLY
#define FLAG_FRIENDLY
Definition: define.h:246
spells.h
guildbuy.ob1
ob1
Definition: guildbuy.py:22
struct_dialog_message
Definition: dialog.h:28
obj::stats
living stats
Definition: object.h:376
MSG_TYPE_SKILL_FAILURE
#define MSG_TYPE_SKILL_FAILURE
Definition: newclient.h:590
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
obj::direction
int8_t direction
Definition: object.h:342
path_data::distance
uint16_t distance
Definition: monster.cpp:418
archt::clone
object clone
Definition: object.h:476
SIZEOFFREE2
#define SIZEOFFREE2
Definition: define.h:154
obj::contr
struct pl * contr
Definition: object.h:282
obj::facing
int8_t facing
Definition: object.h:343
MAX_REPLIES
#define MAX_REPLIES
Definition: dialog.h:45
object_can_pick
int object_can_pick(const object *who, const object *item)
Definition: object.cpp:3860
obj::weight
int32_t weight
Definition: object.h:373
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:2579
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:301
monster_do_say
void monster_do_say(const mapstruct *map, const char *message)
Definition: monster.cpp:2290
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:147
SP_MOVING_BALL
#define SP_MOVING_BALL
Definition: spells.h:109
liv::Wis
int8_t Wis
Definition: living.h:36
liv::grace
int16_t grace
Definition: living.h:44
rt_question
@ rt_question
Definition: dialog.h:12
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:2631
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:1434
monster_use_bow
static int monster_use_bow(object *head, object *part, object *pl, int dir)
Definition: monster.cpp:1567
pets_follow_owner
void pets_follow_owner(object *ob, object *owner)
Definition: pets.cpp:284
rv_vector
Definition: map.h:373
hit_player
int hit_player(object *op, int dam, object *hitter, uint32_t type, int full_hit)
Definition: attack.cpp:1860
get_randomized_dir
int get_randomized_dir(int dir)
Definition: utils.cpp:422
do_hidden_move
void do_hidden_move(object *op)
Definition: player.cpp:3998
diamondslots.y
y
Definition: diamondslots.py:16
NDI_WHITE
#define NDI_WHITE
Definition: newclient.h:243
on_same_map
int on_same_map(const object *op1, const object *op2)
Definition: map.cpp:2665
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:52
pl::hidden
uint32_t hidden
Definition: player.h:147
guild_entry.x1
int x1
Definition: guild_entry.py:33
MSG_TYPE_DIALOG_MAGIC_EAR
#define MSG_TYPE_DIALOG_MAGIC_EAR
Definition: newclient.h:489
obj::head
struct obj * head
Definition: object.h:302
obj::subtype
uint8_t subtype
Definition: object.h:347
obj::more
struct obj * more
Definition: object.h:301
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:487
obj::move_type
MoveType move_type
Definition: object.h:432
fire_bow
int fire_bow(object *op, object *arrow, int dir, int wc_mod, int16_t sx, int16_t sy)
Definition: player.cpp:2073
get_rangevector
int get_rangevector(object *op1, const object *op2, rv_vector *retval, int flags)
Definition: map.cpp:2553
monster_pace_movev
static void monster_pace_movev(object *ob)
Definition: monster.cpp:2184
talk_info::npc_msgs
sstring npc_msgs[MAX_NPC]
Definition: dialog.h:61
npc_dialog.npc
npc
Definition: npc_dialog.py:95
make_face_from_files.int
int
Definition: make_face_from_files.py:26
MIN_ACTIVE_SPEED
#define MIN_ACTIVE_SPEED
Definition: define.h:639
obj::pick_up
uint8_t pick_up
Definition: object.h:369
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:115
monster_stand_in_light
int monster_stand_in_light(object *op)
Definition: monster.cpp:2719
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:129
player_can_view
int player_can_view(object *pl, object *op)
Definition: player.cpp:4107
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:2495
FLAG_READY_RANGE
#define FLAG_READY_RANGE
Definition: define.h:298
SCROLL
@ SCROLL
Definition: object.h:224
monster_talk_to_npc
static int monster_talk_to_npc(object *npc, talk_info *info)
Definition: monster.cpp:2512
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:1350
obj::will_apply
uint8_t will_apply
Definition: object.h:400
object_set_value
int object_set_value(object *op, const char *key, const char *value, int add_key)
Definition: object.cpp:4492
MSG_TYPE_COMMUNICATION
#define MSG_TYPE_COMMUNICATION
Definition: newclient.h:410
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:775
DISTATT
#define DISTATT
Definition: define.h:491
WILL_APPLY_TREASURE
#define WILL_APPLY_TREASURE
Definition: object.h:53
minheap_insert
int minheap_insert(MinHeap *heap, void *ob)
Definition: minheap.cpp:184
freearr_x
short freearr_x[SIZEOFFREE]
Definition: object.cpp:299
mapdef::path
char path[HUGE_BUF]
Definition: map.h:358
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:1264
SPELL
@ SPELL
Definition: object.h:217
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
liv::sp
int16_t sp
Definition: living.h:42
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
mapdef::width
uint16_t width
Definition: map.h:340
CIRCLE1
#define CIRCLE1
Definition: define.h:509
rv_vector::direction
int direction
Definition: map.h:377
dirdiff
int dirdiff(int dir1, int dir2)
Definition: object.cpp:3725
makes_invisible_to
int makes_invisible_to(object *pl, object *mon)
Definition: spell_effect.cpp:767
PACEH2
#define PACEH2
Definition: define.h:516
SP_EXPLOSION
#define SP_EXPLOSION
Definition: spells.h:80
obj::resist
int16_t resist[NROFATTACKS]
Definition: object.h:349
FLAG_IS_THROWN
#define FLAG_IS_THROWN
Definition: define.h:249
THROWN_OBJ
@ THROWN_OBJ
Definition: object.h:149
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:374
SPELLBOOK
@ SPELLBOOK
Definition: object.h:206
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:2260
get_reply_text_own
const char * get_reply_text_own(reply_type rt)
Definition: monster.cpp:2316
monster_dist_att
static int monster_dist_att(int dir, object *enemy, object *part, rv_vector *rv)
Definition: monster.cpp:2052
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:623
drain_wand_charge
void drain_wand_charge(object *wand)
Definition: spell_util.cpp:785
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
obj::level
int16_t level
Definition: object.h:359
monster_communicate
void monster_communicate(object *op, const char *txt)
Definition: monster.cpp:2372
WILL_APPLY_FOOD
#define WILL_APPLY_FOOD
Definition: object.h:56
llevDebug
@ llevDebug
Definition: logger.h:13
MONEY
@ MONEY
Definition: object.h:140
obj::range
int8_t range
Definition: object.h:413
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:2446
monster_check_apply
static void monster_check_apply(object *mon, object *item)
Definition: monster.cpp:1732
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Definition: define.h:302
is_true_undead
int is_true_undead(object *op)
Definition: player.cpp:3933
obj::inv
struct obj * inv
Definition: object.h:296
give.name
name
Definition: give.py:27
skill_attack
void skill_attack(object *tmp, object *pl, int dir, const char *string, object *skill)
Definition: skill_util.cpp:1261
SPELL_MANA
#define SPELL_MANA
Definition: spells.h:58
identify
object * identify(object *op)
Definition: item.cpp:1409
get_reply_text_other
static const char * get_reply_text_other(reply_type rt)
Definition: monster.cpp:2334