Source:NetHack 3.6.1/src/region.c

From NetHackWiki
(Redirected from Source:Ref/mon in region)
Jump to: navigation, search

Below is the full text to region.c from the source code of NetHack 3.6.1. To link to a particular line, write [[Source:NetHack 3.6.1/src/region.c#line123]], for example.

Top of file

  1.  /* NetHack 3.6	region.c	$NHDT-Date: 1496087244 2017/05/29 19:47:24 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.40 $ */
  2.  /* Copyright (c) 1996 by Jean-Christophe Collet  */
  3.  /* NetHack may be freely redistributed.  See license for details. */

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

  1.  
  2.  #include "hack.h"
  3.  #include "lev.h"
  4.  
  5.  /*
  6.   * This should really go into the level structure, but
  7.   * I'll start here for ease. It *WILL* move into the level
  8.   * structure eventually.
  9.   */
  10.  
  11.  static NhRegion **regions;
  12.  static int n_regions = 0;
  13.  static int max_regions = 0;
  14.  
  15.  #define NO_CALLBACK (-1)
  16.  
  17.  boolean FDECL(inside_gas_cloud, (genericptr, genericptr));
  18.  boolean FDECL(expire_gas_cloud, (genericptr, genericptr));
  19.  boolean FDECL(inside_rect, (NhRect *, int, int));
  20.  boolean FDECL(inside_region, (NhRegion *, int, int));
  21.  NhRegion *FDECL(create_region, (NhRect *, int));
  22.  void FDECL(add_rect_to_reg, (NhRegion *, NhRect *));
  23.  void FDECL(add_mon_to_reg, (NhRegion *, struct monst *));
  24.  void FDECL(remove_mon_from_reg, (NhRegion *, struct monst *));
  25.  boolean FDECL(mon_in_region, (NhRegion *, struct monst *));
  26.  
  27.  #if 0
  28.  NhRegion *FDECL(clone_region, (NhRegion *));
  29.  #endif
  30.  void FDECL(free_region, (NhRegion *));
  31.  void FDECL(add_region, (NhRegion *));
  32.  void FDECL(remove_region, (NhRegion *));
  33.  
  34.  #if 0
  35.  void FDECL(replace_mon_regions, (struct monst *,struct monst *));
  36.  void FDECL(remove_mon_from_regions, (struct monst *));
  37.  NhRegion *FDECL(create_msg_region, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P,
  38.                                      const char *,const char *));
  39.  boolean FDECL(enter_force_field, (genericptr,genericptr));
  40.  NhRegion *FDECL(create_force_field, (XCHAR_P,XCHAR_P,int,long));
  41.  #endif
  42.  
  43.  STATIC_DCL void FDECL(reset_region_mids, (NhRegion *));
  44.  
  45.  static callback_proc callbacks[] = {
  46.  #define INSIDE_GAS_CLOUD 0
  47.      inside_gas_cloud,
  48.  #define EXPIRE_GAS_CLOUD 1
  49.      expire_gas_cloud
  50.  };
  51.  

inside_rect

  1.  /* Should be inlined. */
  2.  boolean
  3.  inside_rect(r, x, y)
  4.  NhRect *r;
  5.  int x, y;
  6.  {
  7.      return (boolean) (x >= r->lx && x <= r->hx && y >= r->ly && y <= r->hy);
  8.  }
  9.  

inside_region

  1.  /*
  2.   * Check if a point is inside a region.
  3.   */
  4.  boolean
  5.  inside_region(reg, x, y)
  6.  NhRegion *reg;
  7.  int x, y;
  8.  {
  9.      int i;
  10.  
  11.      if (reg == (NhRegion *) 0 || !inside_rect(&(reg->bounding_box), x, y))
  12.          return FALSE;
  13.      for (i = 0; i < reg->nrects; i++)
  14.          if (inside_rect(&(reg->rects[i]), x, y))
  15.              return TRUE;
  16.      return FALSE;
  17.  }
  18.  

create_region

  1.  /*
  2.   * Create a region. It does not activate it.
  3.   */
  4.  NhRegion *
  5.  create_region(rects, nrect)
  6.  NhRect *rects;
  7.  int nrect;
  8.  {
  9.      int i;
  10.      NhRegion *reg;
  11.  
  12.      reg = (NhRegion *) alloc(sizeof(NhRegion));
  13.      (void) memset((genericptr_t)reg, 0, sizeof(NhRegion));
  14.      /* Determines bounding box */
  15.      if (nrect > 0) {
  16.          reg->bounding_box = rects[0];
  17.      } else {
  18.          reg->bounding_box.lx = COLNO;
  19.          reg->bounding_box.ly = ROWNO;
  20.          reg->bounding_box.hx = 0; /* 1 */
  21.          reg->bounding_box.hy = 0;
  22.      }
  23.      reg->nrects = nrect;
  24.      reg->rects = (nrect > 0) ? (NhRect *) alloc(nrect * sizeof (NhRect)) : 0;
  25.      for (i = 0; i < nrect; i++) {
  26.          if (rects[i].lx < reg->bounding_box.lx)
  27.              reg->bounding_box.lx = rects[i].lx;
  28.          if (rects[i].ly < reg->bounding_box.ly)
  29.              reg->bounding_box.ly = rects[i].ly;
  30.          if (rects[i].hx > reg->bounding_box.hx)
  31.              reg->bounding_box.hx = rects[i].hx;
  32.          if (rects[i].hy > reg->bounding_box.hy)
  33.              reg->bounding_box.hy = rects[i].hy;
  34.          reg->rects[i] = rects[i];
  35.      }
  36.      reg->ttl = -1L; /* Defaults */
  37.      reg->attach_2_u = FALSE;
  38.      reg->attach_2_m = 0;
  39.      /* reg->attach_2_o = NULL; */
  40.      reg->enter_msg = (const char *) 0;
  41.      reg->leave_msg = (const char *) 0;
  42.      reg->expire_f = NO_CALLBACK;
  43.      reg->enter_f = NO_CALLBACK;
  44.      reg->can_enter_f = NO_CALLBACK;
  45.      reg->leave_f = NO_CALLBACK;
  46.      reg->can_leave_f = NO_CALLBACK;
  47.      reg->inside_f = NO_CALLBACK;
  48.      clear_hero_inside(reg);
  49.      clear_heros_fault(reg);
  50.      reg->n_monst = 0;
  51.      reg->max_monst = 0;
  52.      reg->monsters = (unsigned int *) 0;
  53.      reg->arg = zeroany;
  54.      return reg;
  55.  }
  56.  

add_rect_to_reg

  1.  /*
  2.   * Add rectangle to region.
  3.   */
  4.  void
  5.  add_rect_to_reg(reg, rect)
  6.  NhRegion *reg;
  7.  NhRect *rect;
  8.  {
  9.      NhRect *tmp_rect;
  10.  
  11.      tmp_rect = (NhRect *) alloc((reg->nrects + 1) * sizeof (NhRect));
  12.      if (reg->nrects > 0) {
  13.          (void) memcpy((genericptr_t) tmp_rect, (genericptr_t) reg->rects,
  14.                        reg->nrects * sizeof (NhRect));
  15.          free((genericptr_t) reg->rects);
  16.      }
  17.      tmp_rect[reg->nrects] = *rect;
  18.      reg->nrects++;
  19.      reg->rects = tmp_rect;
  20.      /* Update bounding box if needed */
  21.      if (reg->bounding_box.lx > rect->lx)
  22.          reg->bounding_box.lx = rect->lx;
  23.      if (reg->bounding_box.ly > rect->ly)
  24.          reg->bounding_box.ly = rect->ly;
  25.      if (reg->bounding_box.hx < rect->hx)
  26.          reg->bounding_box.hx = rect->hx;
  27.      if (reg->bounding_box.hy < rect->hy)
  28.          reg->bounding_box.hy = rect->hy;
  29.  }
  30.  

add_mon_to_reg

  1.  /*
  2.   * Add a monster to the region
  3.   */
  4.  void
  5.  add_mon_to_reg(reg, mon)
  6.  NhRegion *reg;
  7.  struct monst *mon;
  8.  {
  9.      int i;
  10.      unsigned *tmp_m;
  11.  
  12.      if (reg->max_monst <= reg->n_monst) {
  13.          tmp_m = (unsigned *) alloc(sizeof (unsigned)
  14.                                     * (reg->max_monst + MONST_INC));
  15.          if (reg->max_monst > 0) {
  16.              for (i = 0; i < reg->max_monst; i++)
  17.                  tmp_m[i] = reg->monsters[i];
  18.              free((genericptr_t) reg->monsters);
  19.          }
  20.          reg->monsters = tmp_m;
  21.          reg->max_monst += MONST_INC;
  22.      }
  23.      reg->monsters[reg->n_monst++] = mon->m_id;
  24.  }
  25.  

remove_mon_from_reg

  1.  /*
  2.   * Remove a monster from the region list (it left or died...)
  3.   */
  4.  void
  5.  remove_mon_from_reg(reg, mon)
  6.  NhRegion *reg;
  7.  struct monst *mon;
  8.  {
  9.      register int i;
  10.  
  11.      for (i = 0; i < reg->n_monst; i++)
  12.          if (reg->monsters[i] == mon->m_id) {
  13.              reg->n_monst--;
  14.              reg->monsters[i] = reg->monsters[reg->n_monst];
  15.              return;
  16.          }
  17.  }
  18.  

mon_in_region

  1.  /*
  2.   * Check if a monster is inside the region.
  3.   * It's probably quicker to check with the region internal list
  4.   * than to check for coordinates.
  5.   */
  6.  boolean
  7.  mon_in_region(reg, mon)
  8.  NhRegion *reg;
  9.  struct monst *mon;
  10.  {
  11.      int i;
  12.  
  13.      for (i = 0; i < reg->n_monst; i++)
  14.          if (reg->monsters[i] == mon->m_id)
  15.              return TRUE;
  16.      return FALSE;
  17.  }
  18.  
  19.  #if 0
  20.  /* not yet used */
  21.  
  22.  /*
  23.   * Clone (make a standalone copy) the region.
  24.   */
  25.  NhRegion *
  26.  clone_region(reg)
  27.  NhRegion *reg;
  28.  {
  29.      NhRegion *ret_reg;
  30.  
  31.      ret_reg = create_region(reg->rects, reg->nrects);
  32.      ret_reg->ttl = reg->ttl;
  33.      ret_reg->attach_2_u = reg->attach_2_u;
  34.      ret_reg->attach_2_m = reg->attach_2_m;
  35.   /* ret_reg->attach_2_o = reg->attach_2_o; */
  36.      ret_reg->expire_f = reg->expire_f;
  37.      ret_reg->enter_f = reg->enter_f;
  38.      ret_reg->can_enter_f = reg->can_enter_f;
  39.      ret_reg->leave_f = reg->leave_f;
  40.      ret_reg->can_leave_f = reg->can_leave_f;
  41.      ret_reg->player_flags = reg->player_flags; /* set/clear_hero_inside,&c*/
  42.      ret_reg->n_monst = reg->n_monst;
  43.      if (reg->n_monst > 0) {
  44.          ret_reg->monsters = (unsigned int *)
  45.                                      alloc((sizeof (unsigned)) * reg->n_monst);
  46.          (void) memcpy((genericptr_t) ret_reg->monsters,
  47.                        (genericptr_t) reg->monsters,
  48.                        sizeof (unsigned) * reg->n_monst);
  49.      } else
  50.          ret_reg->monsters = (unsigned int *) 0;
  51.      return ret_reg;
  52.  }
  53.  
  54.  #endif /*0*/
  55.  

free_region

  1.  /*
  2.   * Free mem from region.
  3.   */
  4.  void
  5.  free_region(reg)
  6.  NhRegion *reg;
  7.  {
  8.      if (reg) {
  9.          if (reg->rects)
  10.              free((genericptr_t) reg->rects);
  11.          if (reg->monsters)
  12.              free((genericptr_t) reg->monsters);
  13.          if (reg->enter_msg)
  14.              free((genericptr_t) reg->enter_msg);
  15.          if (reg->leave_msg)
  16.              free((genericptr_t) reg->leave_msg);
  17.          free((genericptr_t) reg);
  18.      }
  19.  }
  20.  

add_region

  1.  /*
  2.   * Add a region to the list.
  3.   * This actually activates the region.
  4.   */
  5.  void
  6.  add_region(reg)
  7.  NhRegion *reg;
  8.  {
  9.      NhRegion **tmp_reg;
  10.      int i, j;
  11.  
  12.      if (max_regions <= n_regions) {
  13.          tmp_reg = regions;
  14.          regions =
  15.              (NhRegion **) alloc((max_regions + 10) * sizeof (NhRegion *));
  16.          if (max_regions > 0) {
  17.              (void) memcpy((genericptr_t) regions, (genericptr_t) tmp_reg,
  18.                            max_regions * sizeof (NhRegion *));
  19.              free((genericptr_t) tmp_reg);
  20.          }
  21.          max_regions += 10;
  22.      }
  23.      regions[n_regions] = reg;
  24.      n_regions++;
  25.      /* Check for monsters inside the region */
  26.      for (i = reg->bounding_box.lx; i <= reg->bounding_box.hx; i++)
  27.          for (j = reg->bounding_box.ly; j <= reg->bounding_box.hy; j++) {
  28.              /* Some regions can cross the level boundaries */
  29.              if (!isok(i, j))
  30.                  continue;
  31.              if (MON_AT(i, j) && inside_region(reg, i, j))
  32.                  add_mon_to_reg(reg, level.monsters[i][j]);
  33.              if (reg->visible && cansee(i, j))
  34.                  newsym(i, j);
  35.          }
  36.      /* Check for player now... */
  37.      if (inside_region(reg, u.ux, u.uy))
  38.          set_hero_inside(reg);
  39.      else
  40.          clear_hero_inside(reg);
  41.  }
  42.  

remove_region

  1.  /*
  2.   * Remove a region from the list & free it.
  3.   */
  4.  void
  5.  remove_region(reg)
  6.  NhRegion *reg;
  7.  {
  8.      register int i, x, y;
  9.  
  10.      for (i = 0; i < n_regions; i++)
  11.          if (regions[i] == reg)
  12.              break;
  13.      if (i == n_regions)
  14.          return;
  15.  
  16.      /* Update screen if necessary */
  17.      reg->ttl = -2L; /* for visible_region_at */
  18.      if (reg->visible)
  19.          for (x = reg->bounding_box.lx; x <= reg->bounding_box.hx; x++)
  20.              for (y = reg->bounding_box.ly; y <= reg->bounding_box.hy; y++)
  21.                  if (isok(x, y) && inside_region(reg, x, y) && cansee(x, y))
  22.                      newsym(x, y);
  23.  
  24.      free_region(reg);
  25.      regions[i] = regions[n_regions - 1];
  26.      regions[n_regions - 1] = (NhRegion *) 0;
  27.      n_regions--;
  28.  }
  29.  

clear_regions

  1.  /*
  2.   * Remove all regions and clear all related data (This must be down
  3.   * when changing level, for instance).
  4.   */
  5.  void
  6.  clear_regions()
  7.  {
  8.      register int i;
  9.  
  10.      for (i = 0; i < n_regions; i++)
  11.          free_region(regions[i]);
  12.      n_regions = 0;
  13.      if (max_regions > 0)
  14.          free((genericptr_t) regions);
  15.      max_regions = 0;
  16.      regions = (NhRegion **) 0;
  17.  }
  18.  

run_regions

  1.  /*
  2.   * This function is called every turn.
  3.   * It makes the regions age, if necessary and calls the appropriate
  4.   * callbacks when needed.
  5.   */
  6.  void
  7.  run_regions()
  8.  {
  9.      register int i, j, k;
  10.      int f_indx;
  11.  
  12.      /* End of life ? */
  13.      /* Do it backward because the array will be modified */
  14.      for (i = n_regions - 1; i >= 0; i--) {
  15.          if (regions[i]->ttl == 0L) {
  16.              if ((f_indx = regions[i]->expire_f) == NO_CALLBACK
  17.                  || (*callbacks[f_indx])(regions[i], (genericptr_t) 0))
  18.                  remove_region(regions[i]);
  19.          }
  20.      }
  21.  
  22.      /* Process remaining regions */
  23.      for (i = 0; i < n_regions; i++) {
  24.          /* Make the region age */
  25.          if (regions[i]->ttl > 0L)
  26.              regions[i]->ttl--;
  27.          /* Check if player is inside region */
  28.          f_indx = regions[i]->inside_f;
  29.          if (f_indx != NO_CALLBACK && hero_inside(regions[i]))
  30.              (void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0);
  31.          /* Check if any monster is inside region */
  32.          if (f_indx != NO_CALLBACK) {
  33.              for (j = 0; j < regions[i]->n_monst; j++) {
  34.                  struct monst *mtmp =
  35.                      find_mid(regions[i]->monsters[j], FM_FMON);
  36.  
  37.                  if (!mtmp || mtmp->mhp <= 0
  38.                      || (*callbacks[f_indx])(regions[i], mtmp)) {
  39.                      /* The monster died, remove it from list */
  40.                      k = (regions[i]->n_monst -= 1);
  41.                      regions[i]->monsters[j] = regions[i]->monsters[k];
  42.                      regions[i]->monsters[k] = 0;
  43.                      --j; /* current slot has been reused; recheck it next */
  44.                  }
  45.              }
  46.          }
  47.      }
  48.  }
  49.  

in_out_region

  1.  /*
  2.   * check whether player enters/leaves one or more regions.
  3.   */
  4.  boolean
  5.  in_out_region(x, y)
  6.  xchar x, y;
  7.  {
  8.      int i, f_indx;
  9.  
  10.      /* First check if we can do the move */
  11.      for (i = 0; i < n_regions; i++) {
  12.          if (inside_region(regions[i], x, y) && !hero_inside(regions[i])
  13.              && !regions[i]->attach_2_u) {
  14.              if ((f_indx = regions[i]->can_enter_f) != NO_CALLBACK)
  15.                  if (!(*callbacks[f_indx])(regions[i], (genericptr_t) 0))
  16.                      return FALSE;
  17.          } else if (hero_inside(regions[i]) && !inside_region(regions[i], x, y)
  18.                     && !regions[i]->attach_2_u) {
  19.              if ((f_indx = regions[i]->can_leave_f) != NO_CALLBACK)
  20.                  if (!(*callbacks[f_indx])(regions[i], (genericptr_t) 0))
  21.                      return FALSE;
  22.          }
  23.      }
  24.  
  25.      /* Callbacks for the regions we do leave */
  26.      for (i = 0; i < n_regions; i++)
  27.          if (hero_inside(regions[i]) && !regions[i]->attach_2_u
  28.              && !inside_region(regions[i], x, y)) {
  29.              clear_hero_inside(regions[i]);
  30.              if (regions[i]->leave_msg != (const char *) 0)
  31.                  pline1(regions[i]->leave_msg);
  32.              if ((f_indx = regions[i]->leave_f) != NO_CALLBACK)
  33.                  (void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0);
  34.          }
  35.  
  36.      /* Callbacks for the regions we do enter */
  37.      for (i = 0; i < n_regions; i++)
  38.          if (!hero_inside(regions[i]) && !regions[i]->attach_2_u
  39.              && inside_region(regions[i], x, y)) {
  40.              set_hero_inside(regions[i]);
  41.              if (regions[i]->enter_msg != (const char *) 0)
  42.                  pline1(regions[i]->enter_msg);
  43.              if ((f_indx = regions[i]->enter_f) != NO_CALLBACK)
  44.                  (void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0);
  45.          }
  46.      return TRUE;
  47.  }
  48.  

m_in_out_region

  1.  /*
  2.   * check whether a monster enters/leaves one or more region.
  3.  */
  4.  boolean
  5.  m_in_out_region(mon, x, y)
  6.  struct monst *mon;
  7.  xchar x, y;
  8.  {
  9.      int i, f_indx;
  10.  
  11.      /* First check if we can do the move */
  12.      for (i = 0; i < n_regions; i++) {
  13.          if (inside_region(regions[i], x, y) && !mon_in_region(regions[i], mon)
  14.              && regions[i]->attach_2_m != mon->m_id) {
  15.              if ((f_indx = regions[i]->can_enter_f) != NO_CALLBACK)
  16.                  if (!(*callbacks[f_indx])(regions[i], mon))
  17.                      return FALSE;
  18.          } else if (mon_in_region(regions[i], mon)
  19.                     && !inside_region(regions[i], x, y)
  20.                     && regions[i]->attach_2_m != mon->m_id) {
  21.              if ((f_indx = regions[i]->can_leave_f) != NO_CALLBACK)
  22.                  if (!(*callbacks[f_indx])(regions[i], mon))
  23.                      return FALSE;
  24.          }
  25.      }
  26.  
  27.      /* Callbacks for the regions we do leave */
  28.      for (i = 0; i < n_regions; i++)
  29.          if (mon_in_region(regions[i], mon)
  30.              && regions[i]->attach_2_m != mon->m_id
  31.              && !inside_region(regions[i], x, y)) {
  32.              remove_mon_from_reg(regions[i], mon);
  33.              if ((f_indx = regions[i]->leave_f) != NO_CALLBACK)
  34.                  (void) (*callbacks[f_indx])(regions[i], mon);
  35.          }
  36.  
  37.      /* Callbacks for the regions we do enter */
  38.      for (i = 0; i < n_regions; i++)
  39.          if (!hero_inside(regions[i]) && !regions[i]->attach_2_u
  40.              && inside_region(regions[i], x, y)) {
  41.              add_mon_to_reg(regions[i], mon);
  42.              if ((f_indx = regions[i]->enter_f) != NO_CALLBACK)
  43.                  (void) (*callbacks[f_indx])(regions[i], mon);
  44.          }
  45.      return TRUE;
  46.  }
  47.  

update_player_regions

  1.  /*
  2.   * Checks player's regions after a teleport for instance.
  3.   */
  4.  void
  5.  update_player_regions()
  6.  {
  7.      register int i;
  8.  
  9.      for (i = 0; i < n_regions; i++)
  10.          if (!regions[i]->attach_2_u && inside_region(regions[i], u.ux, u.uy))
  11.              set_hero_inside(regions[i]);
  12.          else
  13.              clear_hero_inside(regions[i]);
  14.  }
  15.  

update_monster_region

  1.  /*
  2.   * Ditto for a specified monster.
  3.   */
  4.  void
  5.  update_monster_region(mon)
  6.  struct monst *mon;
  7.  {
  8.      register int i;
  9.  
  10.      for (i = 0; i < n_regions; i++) {
  11.          if (inside_region(regions[i], mon->mx, mon->my)) {
  12.              if (!mon_in_region(regions[i], mon))
  13.                  add_mon_to_reg(regions[i], mon);
  14.          } else {
  15.              if (mon_in_region(regions[i], mon))
  16.                  remove_mon_from_reg(regions[i], mon);
  17.          }
  18.      }
  19.  }
  20.  
  21.  #if 0
  22.  /* not yet used */
  23.  
  24.  /*
  25.   * Change monster pointer in regions
  26.   * This happens, for instance, when a monster grows and
  27.   * need a new structure (internally that is).
  28.   */
  29.  void
  30.  replace_mon_regions(monold, monnew)
  31.  struct monst *monold, *monnew;
  32.  {
  33.      register int i;
  34.  
  35.      for (i = 0; i < n_regions; i++)
  36.          if (mon_in_region(regions[i], monold)) {
  37.              remove_mon_from_reg(regions[i], monold);
  38.              add_mon_to_reg(regions[i], monnew);
  39.          }
  40.  }
  41.  
  42.  /*
  43.   * Remove monster from all regions it was in (ie monster just died)
  44.   */
  45.  void
  46.  remove_mon_from_regions(mon)
  47.  struct monst *mon;
  48.  {
  49.      register int i;
  50.  
  51.      for (i = 0; i < n_regions; i++)
  52.          if (mon_in_region(regions[i], mon))
  53.              remove_mon_from_reg(regions[i], mon);
  54.  }
  55.  
  56.  #endif /*0*/
  57.  

visible_region_at

  1.  /*
  2.   * Check if a spot is under a visible region (eg: gas cloud).
  3.   * Returns NULL if not, otherwise returns region.
  4.   */
  5.  NhRegion *
  6.  visible_region_at(x, y)
  7.  xchar x, y;
  8.  {
  9.      register int i;
  10.  
  11.      for (i = 0; i < n_regions; i++)
  12.          if (inside_region(regions[i], x, y) && regions[i]->visible
  13.              && regions[i]->ttl != -2L)
  14.              return regions[i];
  15.      return (NhRegion *) 0;
  16.  }
  17.  

show_region

  1.  void
  2.  show_region(reg, x, y)
  3.  NhRegion *reg;
  4.  xchar x, y;
  5.  {
  6.      show_glyph(x, y, reg->glyph);
  7.  }
  8.  

save_regions

  1.  /**
  2.   * save_regions :
  3.   */
  4.  void
  5.  save_regions(fd, mode)
  6.  int fd;
  7.  int mode;
  8.  {
  9.      int i, j;
  10.      unsigned n;
  11.  
  12.      if (!perform_bwrite(mode))
  13.          goto skip_lots;
  14.  
  15.      bwrite(fd, (genericptr_t) &moves, sizeof(moves)); /* timestamp */
  16.      bwrite(fd, (genericptr_t) &n_regions, sizeof(n_regions));
  17.      for (i = 0; i < n_regions; i++) {
  18.          bwrite(fd, (genericptr_t) &regions[i]->bounding_box, sizeof(NhRect));
  19.          bwrite(fd, (genericptr_t) &regions[i]->nrects, sizeof(short));
  20.          for (j = 0; j < regions[i]->nrects; j++)
  21.              bwrite(fd, (genericptr_t) &regions[i]->rects[j], sizeof(NhRect));
  22.          bwrite(fd, (genericptr_t) &regions[i]->attach_2_u, sizeof(boolean));
  23.          n = 0;
  24.          bwrite(fd, (genericptr_t) &regions[i]->attach_2_m, sizeof(unsigned));
  25.          n = regions[i]->enter_msg != (const char *) 0
  26.                  ? strlen(regions[i]->enter_msg)
  27.                  : 0;
  28.          bwrite(fd, (genericptr_t) &n, sizeof n);
  29.          if (n > 0)
  30.              bwrite(fd, (genericptr_t) regions[i]->enter_msg, n);
  31.          n = regions[i]->leave_msg != (const char *) 0
  32.                  ? strlen(regions[i]->leave_msg)
  33.                  : 0;
  34.          bwrite(fd, (genericptr_t) &n, sizeof n);
  35.          if (n > 0)
  36.              bwrite(fd, (genericptr_t) regions[i]->leave_msg, n);
  37.          bwrite(fd, (genericptr_t) &regions[i]->ttl, sizeof(long));
  38.          bwrite(fd, (genericptr_t) &regions[i]->expire_f, sizeof(short));
  39.          bwrite(fd, (genericptr_t) &regions[i]->can_enter_f, sizeof(short));
  40.          bwrite(fd, (genericptr_t) &regions[i]->enter_f, sizeof(short));
  41.          bwrite(fd, (genericptr_t) &regions[i]->can_leave_f, sizeof(short));
  42.          bwrite(fd, (genericptr_t) &regions[i]->leave_f, sizeof(short));
  43.          bwrite(fd, (genericptr_t) &regions[i]->inside_f, sizeof(short));
  44.          bwrite(fd, (genericptr_t) &regions[i]->player_flags,
  45.                 sizeof(unsigned int));
  46.          bwrite(fd, (genericptr_t) &regions[i]->n_monst, sizeof(short));
  47.          for (j = 0; j < regions[i]->n_monst; j++)
  48.              bwrite(fd, (genericptr_t) &regions[i]->monsters[j],
  49.                     sizeof(unsigned));
  50.          bwrite(fd, (genericptr_t) &regions[i]->visible, sizeof(boolean));
  51.          bwrite(fd, (genericptr_t) &regions[i]->glyph, sizeof(int));
  52.          bwrite(fd, (genericptr_t) &regions[i]->arg, sizeof(anything));
  53.      }
  54.  
  55.  skip_lots:
  56.      if (release_data(mode))
  57.          clear_regions();
  58.  }
  59.  

rest_regions

  1.  void
  2.  rest_regions(fd, ghostly)
  3.  int fd;
  4.  boolean ghostly; /* If a bones file restore */
  5.  {
  6.      int i, j;
  7.      unsigned n;
  8.      long tmstamp;
  9.      char *msg_buf;
  10.  
  11.      clear_regions(); /* Just for security */
  12.      mread(fd, (genericptr_t) &tmstamp, sizeof(tmstamp));
  13.      if (ghostly)
  14.          tmstamp = 0;
  15.      else
  16.          tmstamp = (moves - tmstamp);
  17.      mread(fd, (genericptr_t) &n_regions, sizeof(n_regions));
  18.      max_regions = n_regions;
  19.      if (n_regions > 0)
  20.          regions = (NhRegion **) alloc(sizeof(NhRegion *) * n_regions);
  21.      for (i = 0; i < n_regions; i++) {
  22.          regions[i] = (NhRegion *) alloc(sizeof(NhRegion));
  23.          mread(fd, (genericptr_t) &regions[i]->bounding_box, sizeof(NhRect));
  24.          mread(fd, (genericptr_t) &regions[i]->nrects, sizeof(short));
  25.  
  26.          if (regions[i]->nrects > 0)
  27.              regions[i]->rects =
  28.                  (NhRect *) alloc(sizeof(NhRect) * regions[i]->nrects);
  29.          for (j = 0; j < regions[i]->nrects; j++)
  30.              mread(fd, (genericptr_t) &regions[i]->rects[j], sizeof(NhRect));
  31.          mread(fd, (genericptr_t) &regions[i]->attach_2_u, sizeof(boolean));
  32.          mread(fd, (genericptr_t) &regions[i]->attach_2_m, sizeof(unsigned));
  33.  
  34.          mread(fd, (genericptr_t) &n, sizeof n);
  35.          if (n > 0) {
  36.              msg_buf = (char *) alloc(n + 1);
  37.              mread(fd, (genericptr_t) msg_buf, n);
  38.              msg_buf[n] = '\0';
  39.              regions[i]->enter_msg = (const char *) msg_buf;
  40.          } else
  41.              regions[i]->enter_msg = (const char *) 0;
  42.  
  43.          mread(fd, (genericptr_t) &n, sizeof n);
  44.          if (n > 0) {
  45.              msg_buf = (char *) alloc(n + 1);
  46.              mread(fd, (genericptr_t) msg_buf, n);
  47.              msg_buf[n] = '\0';
  48.              regions[i]->leave_msg = (const char *) msg_buf;
  49.          } else
  50.              regions[i]->leave_msg = (const char *) 0;
  51.  
  52.          mread(fd, (genericptr_t) &regions[i]->ttl, sizeof(long));
  53.          /* check for expired region */
  54.          if (regions[i]->ttl >= 0L)
  55.              regions[i]->ttl =
  56.                  (regions[i]->ttl > tmstamp) ? regions[i]->ttl - tmstamp : 0L;
  57.          mread(fd, (genericptr_t) &regions[i]->expire_f, sizeof(short));
  58.          mread(fd, (genericptr_t) &regions[i]->can_enter_f, sizeof(short));
  59.          mread(fd, (genericptr_t) &regions[i]->enter_f, sizeof(short));
  60.          mread(fd, (genericptr_t) &regions[i]->can_leave_f, sizeof(short));
  61.          mread(fd, (genericptr_t) &regions[i]->leave_f, sizeof(short));
  62.          mread(fd, (genericptr_t) &regions[i]->inside_f, sizeof(short));
  63.          mread(fd, (genericptr_t) &regions[i]->player_flags,
  64.                sizeof(unsigned int));
  65.          if (ghostly) { /* settings pertained to old player */
  66.              clear_hero_inside(regions[i]);
  67.              clear_heros_fault(regions[i]);
  68.          }
  69.          mread(fd, (genericptr_t) &regions[i]->n_monst, sizeof(short));
  70.          if (regions[i]->n_monst > 0)
  71.              regions[i]->monsters =
  72.                  (unsigned *) alloc(sizeof(unsigned) * regions[i]->n_monst);
  73.          else
  74.              regions[i]->monsters = (unsigned int *) 0;
  75.          regions[i]->max_monst = regions[i]->n_monst;
  76.          for (j = 0; j < regions[i]->n_monst; j++)
  77.              mread(fd, (genericptr_t) &regions[i]->monsters[j],
  78.                    sizeof(unsigned));
  79.          mread(fd, (genericptr_t) &regions[i]->visible, sizeof(boolean));
  80.          mread(fd, (genericptr_t) &regions[i]->glyph, sizeof(int));
  81.          mread(fd, (genericptr_t) &regions[i]->arg, sizeof(anything));
  82.      }
  83.      /* remove expired regions, do not trigger the expire_f callback (yet!);
  84.         also update monster lists if this data is coming from a bones file */
  85.      for (i = n_regions - 1; i >= 0; i--)
  86.          if (regions[i]->ttl == 0L)
  87.              remove_region(regions[i]);
  88.          else if (ghostly && regions[i]->n_monst > 0)
  89.              reset_region_mids(regions[i]);
  90.  }
  91.  

region_stats

  1.  /* to support '#stats' wizard-mode command */
  2.  void
  3.  region_stats(hdrfmt, hdrbuf, count, size)
  4.  const char *hdrfmt;
  5.  char *hdrbuf;
  6.  long *count, *size;
  7.  {
  8.      NhRegion *rg;
  9.      int i;
  10.  
  11.      /* other stats formats take one parameter; this takes two */
  12.      Sprintf(hdrbuf, hdrfmt, (long) sizeof (NhRegion), (long) sizeof (NhRect));
  13.      *count = (long) n_regions; /* might be 0 even though max_regions isn't */
  14.      *size = (long) max_regions * (long) sizeof (NhRegion);
  15.      for (i = 0; i < n_regions; ++i) {
  16.          rg = regions[i];
  17.          *size += (long) rg->nrects * (long) sizeof (NhRect);
  18.          if (rg->enter_msg)
  19.              *size += (long) (strlen(rg->enter_msg) + 1);
  20.          if (rg->leave_msg)
  21.              *size += (long) (strlen(rg->leave_msg) + 1);
  22.          *size += (long) rg->max_monst * (long) sizeof *rg->monsters;
  23.      }
  24.      /* ? */
  25.  }
  26.  

reset_region_mids

  1.  /* update monster IDs for region being loaded from bones; `ghostly' implied */
  2.  STATIC_OVL void
  3.  reset_region_mids(reg)
  4.  NhRegion *reg;
  5.  {
  6.      int i = 0, n = reg->n_monst;
  7.      unsigned *mid_list = reg->monsters;
  8.  
  9.      while (i < n)
  10.          if (!lookup_id_mapping(mid_list[i], &mid_list[i])) {
  11.              /* shrink list to remove missing monster; order doesn't matter */
  12.              mid_list[i] = mid_list[--n];
  13.          } else {
  14.              /* move on to next monster */
  15.              ++i;
  16.          }
  17.      reg->n_monst = n;
  18.      return;
  19.  }
  20.  
  21.  #if 0
  22.  /* not yet used */
  23.  
  24.  /*--------------------------------------------------------------*
  25.   *                                                              *
  26.   *                      Create Region with just a message       *
  27.   *                                                              *
  28.   *--------------------------------------------------------------*/
  29.  
  30.  NhRegion *
  31.  create_msg_region(x, y, w, h, msg_enter, msg_leave)
  32.  xchar x, y;
  33.  xchar w, h;
  34.  const char *msg_enter;
  35.  const char *msg_leave;
  36.  {
  37.      NhRect tmprect;
  38.      NhRegion *reg = create_region((NhRect *) 0, 0);
  39.  
  40.      if (msg_enter)
  41.          reg->enter_msg = dupstr(msg_enter);
  42.      if (msg_leave)
  43.          reg->leave_msg = dupstr(msg_leave);
  44.      tmprect.lx = x;
  45.      tmprect.ly = y;
  46.      tmprect.hx = x + w;
  47.      tmprect.hy = y + h;
  48.      add_rect_to_reg(reg, &tmprect);
  49.      reg->ttl = -1L;
  50.      return reg;
  51.  }
  52.  
  53.  
  54.  /*--------------------------------------------------------------*
  55.   *                                                              *
  56.   *                      Force Field Related Cod                 *
  57.   *                      (unused yet)                            *
  58.   *--------------------------------------------------------------*/
  59.  
  60.  boolean
  61.  enter_force_field(p1, p2)
  62.  genericptr_t p1;
  63.  genericptr_t p2;
  64.  {
  65.      struct monst *mtmp;
  66.  
  67.      if (p2 == (genericptr_t) 0) { /* That means the player */
  68.          if (!Blind)
  69.              You("bump into %s. Ouch!",
  70.                  Hallucination ? "an invisible tree"
  71.                                : "some kind of invisible wall");
  72.          else
  73.              pline("Ouch!");
  74.      } else {
  75.          mtmp = (struct monst *) p2;
  76.          if (canseemon(mtmp))
  77.              pline("%s bumps into %s!", Monnam(mtmp), something);
  78.      }
  79.      return FALSE;
  80.  }
  81.  
  82.  NhRegion *
  83.  create_force_field(x, y, radius, ttl)
  84.  xchar x, y;
  85.  int radius;
  86.  long ttl;
  87.  {
  88.      int i;
  89.      NhRegion *ff;
  90.      int nrect;
  91.      NhRect tmprect;
  92.  
  93.      ff = create_region((NhRect *) 0, 0);
  94.      nrect = radius;
  95.      tmprect.lx = x;
  96.      tmprect.hx = x;
  97.      tmprect.ly = y - (radius - 1);
  98.      tmprect.hy = y + (radius - 1);
  99.      for (i = 0; i < nrect; i++) {
  100.          add_rect_to_reg(ff, &tmprect);
  101.          tmprect.lx--;
  102.          tmprect.hx++;
  103.          tmprect.ly++;
  104.          tmprect.hy--;
  105.      }
  106.      ff->ttl = ttl;
  107.      if (!in_mklev && !context.mon_moving)
  108.          set_heros_fault(ff); /* assume player has created it */
  109.   /* ff->can_enter_f = enter_force_field; */
  110.   /* ff->can_leave_f = enter_force_field; */
  111.      add_region(ff);
  112.      return ff;
  113.  }
  114.  
  115.  #endif /*0*/
  116.  
  117.  /*--------------------------------------------------------------*
  118.   *                                                              *
  119.   *                      Gas cloud related code                  *
  120.   *                                                              *
  121.   *--------------------------------------------------------------*/
  122.  

expire_gas_cloud

  1.  /*
  2.   * Here is an example of an expire function that may prolong
  3.   * region life after some mods...
  4.   */
  5.  /*ARGSUSED*/
  6.  boolean
  7.  expire_gas_cloud(p1, p2)
  8.  genericptr_t p1;
  9.  genericptr_t p2 UNUSED;
  10.  {
  11.      NhRegion *reg;
  12.      int damage;
  13.  
  14.      reg = (NhRegion *) p1;
  15.      damage = reg->arg.a_int;
  16.  
  17.      /* If it was a thick cloud, it dissipates a little first */
  18.      if (damage >= 5) {
  19.          damage /= 2; /* It dissipates, let's do less damage */
  20.          reg->arg = zeroany;
  21.          reg->arg.a_int = damage;
  22.          reg->ttl = 2L; /* Here's the trick : reset ttl */
  23.          return FALSE;  /* THEN return FALSE, means "still there" */
  24.      }
  25.      return TRUE; /* OK, it's gone, you can free it! */
  26.  }
  27.  

inside_gas_cloud

  1.  boolean
  2.  inside_gas_cloud(p1, p2)
  3.  genericptr_t p1;
  4.  genericptr_t p2;
  5.  {
  6.      NhRegion *reg;
  7.      struct monst *mtmp;
  8.      int dam;
  9.  
  10.      reg = (NhRegion *) p1;
  11.      dam = reg->arg.a_int;
  12.      if (p2 == (genericptr_t) 0) { /* This means *YOU* Bozo! */
  13.          if (u.uinvulnerable || nonliving(youmonst.data) || Breathless)
  14.              return FALSE;
  15.          if (!Blind) {
  16.              Your("%s sting.", makeplural(body_part(EYE)));
  17.              make_blinded(1L, FALSE);
  18.          }
  19.          if (!Poison_resistance) {
  20.              pline("%s is burning your %s!", Something,
  21.                    makeplural(body_part(LUNG)));
  22.              You("cough and spit blood!");
  23.              losehp(Maybe_Half_Phys(rnd(dam) + 5), "gas cloud", KILLED_BY_AN);
  24.              return FALSE;
  25.          } else {
  26.              You("cough!");
  27.              return FALSE;
  28.          }
  29.      } else { /* A monster is inside the cloud */
  30.          mtmp = (struct monst *) p2;
  31.  
  32.          /* Non living and non breathing monsters are not concerned;
  33.             adult green dragon is not affected by gas cloud, baby one is */
  34.          if (!(nonliving(mtmp->data) || is_vampshifter(mtmp))
  35.              && !breathless(mtmp->data)
  36.              /* exclude monsters with poison gas breath attack:
  37.                 adult green dragon and Chromatic Dragon (and iron golem,
  38.                 but nonliving() and breathless() tests also catch that) */
  39.              && !(attacktype_fordmg(mtmp->data, AT_BREA, AD_DRST)
  40.                   || attacktype_fordmg(mtmp->data, AT_BREA, AD_RBRE))) {
  41.              if (cansee(mtmp->mx, mtmp->my))
  42.                  pline("%s coughs!", Monnam(mtmp));
  43.              if (heros_fault(reg))
  44.                  setmangry(mtmp, TRUE);
  45.              if (haseyes(mtmp->data) && mtmp->mcansee) {
  46.                  mtmp->mblinded = 1;
  47.                  mtmp->mcansee = 0;
  48.              }
  49.              if (resists_poison(mtmp))
  50.                  return FALSE;
  51.              mtmp->mhp -= rnd(dam) + 5;
  52.              if (mtmp->mhp <= 0) {
  53.                  if (heros_fault(reg))
  54.                      killed(mtmp);
  55.                  else
  56.                      monkilled(mtmp, "gas cloud", AD_DRST);
  57.                  if (mtmp->mhp <= 0) { /* not lifesaved */
  58.                      return TRUE;
  59.                  }
  60.              }
  61.          }
  62.      }
  63.      return FALSE; /* Monster is still alive */
  64.  }
  65.  

create_gas_cloud

  1.  NhRegion *
  2.  create_gas_cloud(x, y, radius, damage)
  3.  xchar x, y;
  4.  int radius;
  5.  int damage;
  6.  {
  7.      NhRegion *cloud;
  8.      int i, nrect;
  9.      NhRect tmprect;
  10.  
  11.      cloud = create_region((NhRect *) 0, 0);
  12.      nrect = radius;
  13.      tmprect.lx = x;
  14.      tmprect.hx = x;
  15.      tmprect.ly = y - (radius - 1);
  16.      tmprect.hy = y + (radius - 1);
  17.      for (i = 0; i < nrect; i++) {
  18.          add_rect_to_reg(cloud, &tmprect);
  19.          tmprect.lx--;
  20.          tmprect.hx++;
  21.          tmprect.ly++;
  22.          tmprect.hy--;
  23.      }
  24.      cloud->ttl = rn1(3, 4);
  25.      if (!in_mklev && !context.mon_moving)
  26.          set_heros_fault(cloud); /* assume player has created it */
  27.      cloud->inside_f = INSIDE_GAS_CLOUD;
  28.      cloud->expire_f = EXPIRE_GAS_CLOUD;
  29.      cloud->arg = zeroany;
  30.      cloud->arg.a_int = damage;
  31.      cloud->visible = TRUE;
  32.      cloud->glyph = cmap_to_glyph(damage ? S_poisoncloud : S_cloud);
  33.      add_region(cloud);
  34.      return cloud;
  35.  }
  36.  

region_danger

  1.  /* for checking troubles during prayer; is hero at risk? */
  2.  boolean
  3.  region_danger()
  4.  {
  5.      int i, f_indx, n = 0;
  6.  
  7.      for (i = 0; i < n_regions; i++) {
  8.          /* only care about regions that hero is in */
  9.          if (!hero_inside(regions[i]))
  10.              continue;
  11.          f_indx = regions[i]->inside_f;
  12.          /* the only type of region we understand is gas_cloud */
  13.          if (f_indx == INSIDE_GAS_CLOUD) {
  14.              /* completely harmless if you don't need to breathe */
  15.              if (nonliving(youmonst.data) || Breathless)
  16.                  continue;
  17.              /* minor inconvenience if you're poison resistant;
  18.                 not harmful enough to be a prayer-level trouble */
  19.              if (Poison_resistance)
  20.                  continue;
  21.              ++n;
  22.          }
  23.      }
  24.      return n ? TRUE : FALSE;
  25.  }
  26.  

region_safety

  1.  /* for fixing trouble at end of prayer;
  2.     danger detected at start of prayer might have expired by now */
  3.  void
  4.  region_safety()
  5.  {
  6.      NhRegion *r = 0;
  7.      int i, f_indx, n = 0;
  8.  
  9.      for (i = 0; i < n_regions; i++) {
  10.          /* only care about regions that hero is in */
  11.          if (!hero_inside(regions[i]))
  12.              continue;
  13.          f_indx = regions[i]->inside_f;
  14.          /* the only type of region we understand is gas_cloud */
  15.          if (f_indx == INSIDE_GAS_CLOUD) {
  16.              if (!n++ && regions[i]->ttl >= 0)
  17.                  r = regions[i];
  18.          }
  19.      }
  20.  
  21.      if (n > 1 || (n == 1 && !r)) {
  22.          /* multiple overlapping cloud regions or non-expiring one */
  23.          safe_teleds(FALSE);
  24.      } else if (r) {
  25.          remove_region(r);
  26.          pline_The("gas cloud enveloping you dissipates.");
  27.      } else {
  28.          /* cloud dissipated on its own, so nothing needs to be done */
  29.          pline_The("gas cloud has dissipated.");
  30.      }
  31.      /* maybe cure blindness too */
  32.      if ((Blinded & TIMEOUT) == 1L)
  33.          make_blinded(0L, TRUE);
  34.  }
  35.  
  36.  /*region.c*/