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