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