Source:NetHack 3.4.0/region.c

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

Warning! This is the source code from an old release. For the latest release, see Source code

1.   /*	SCCS Id: @(#)region.c	3.4	1999/12/29	*/ 2.   /* Copyright (c) 1996 by Jean-Christophe Collet	 */ 3.   /* NetHack may be freely redistributed. See license for details. */ 4.     5.    #include "hack.h"  6.    #include "lev.h"  7. 8.   /*  9.     * This should really go into the level structure, but 10.   * I'll start here for ease. It *WILL* move into the level 11.   * structure eventually. 12.   */  13.    14.   static NhRegion **regions; 15.  static int n_regions = 0; 16.  static int max_regions = 0; 17.   18.   #define NO_CALLBACK (-1) 19.   20.   boolean FDECL(inside_gas_cloud, (genericptr,genericptr)); 21.  boolean FDECL(expire_gas_cloud, (genericptr,genericptr)); 22.  boolean FDECL(inside_rect, (NhRect *,int,int)); 23.  boolean FDECL(inside_region, (NhRegion *,int,int)); 24.  NhRegion *FDECL(create_region, (NhRect *,int)); 25.  void FDECL(add_rect_to_reg, (NhRegion *,NhRect *)); 26.  void FDECL(add_mon_to_reg, (NhRegion *,struct monst *)); 27.  void FDECL(remove_mon_from_reg, (NhRegion *,struct monst *)); 28.  boolean FDECL(mon_in_region, (NhRegion *,struct monst *)); 29.   30.   #if 0 31.  NhRegion *FDECL(clone_region, (NhRegion *)); 32.  #endif 33.  void FDECL(free_region, (NhRegion *)); 34.  void FDECL(add_region, (NhRegion *)); 35.  void FDECL(remove_region, (NhRegion *)); 36.   37.   #if 0 38.  void FDECL(replace_mon_regions, (struct monst *,struct monst *)); 39.  void FDECL(remove_mon_from_regions, (struct monst *)); 40.  NhRegion *FDECL(create_msg_region, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P, 41.  				    const char *,const char *)); 42.  boolean FDECL(enter_force_field, (genericptr,genericptr)); 43.  NhRegion *FDECL(create_force_field, (XCHAR_P,XCHAR_P,int,int)); 44.  #endif 45.   46.    47.   static callback_proc callbacks[] = { 48.  #define INSIDE_GAS_CLOUD 0 49.      inside_gas_cloud, 50.  #define EXPIRE_GAS_CLOUD 1 51.      expire_gas_cloud 52.  };  53.    54.   /* Should be inlined. */ 55.   boolean 56.  inside_rect(r, x, y)  57. NhRect *r; 58.  int x, y;  59. { 60.       return (x >= r->lx && x <= r->hx && y >= r->ly && y <= r->hy); 61.  }  62.    63.   /*  64.    * Check if a point is inside a region. 65.   */  66.   boolean 67.  inside_region(reg, x, y)  68. NhRegion *reg; 69.  int x, y;  70. { 71.       int i;  72. 73.      if (reg == NULL || !inside_rect(&(reg->bounding_box), x, y)) 74.  	return FALSE; 75.      for (i = 0; i < reg->nrects; i++) 76.  	if (inside_rect(&(reg->rects[i]), x, y)) 77.  	    return TRUE; 78.      return FALSE; 79.  }  80.    81.   /*  82.    * Create a region. It does not activate it. 83.   */  84.   NhRegion * 85.  create_region(rects, nrect) 86.  NhRect *rects; 87.  int nrect; 88.  {  89.       int i;  90. NhRegion *reg; 91.   92.       reg = (NhRegion *) alloc(sizeof (NhRegion)); 93.      /* Determines bounding box */ 94.      if (nrect > 0) { 95.  	reg->bounding_box = rects[0]; 96.      } else { 97.  	reg->bounding_box.lx = 99; 98.  	reg->bounding_box.ly = 99; 99.  	reg->bounding_box.hx = 0; 100. 	reg->bounding_box.hy = 0; 101.     }  102.      reg->nrects = nrect; 103.     reg->rects = nrect > 0 ? (NhRect *)alloc((sizeof (NhRect)) * nrect) : NULL; 104.     for (i = 0; i < nrect; i++) { 105. 	if (rects[i].lx < reg->bounding_box.lx) 106. 	    reg->bounding_box.lx = rects[i].lx; 107. 	if (rects[i].ly < reg->bounding_box.ly) 108. 	    reg->bounding_box.ly = rects[i].ly; 109. 	if (rects[i].hx > reg->bounding_box.hx) 110. 	    reg->bounding_box.hx = rects[i].hx; 111. 	if (rects[i].hy > reg->bounding_box.hy) 112. 	    reg->bounding_box.hy = rects[i].hy; 113. 	reg->rects[i] = rects[i]; 114.     }  115.      reg->ttl = -1;		/* Defaults */ 116.     reg->attach_2_u = FALSE; 117.     reg->attach_2_m = 0; 118.     /* reg->attach_2_o = NULL; */ 119.     reg->enter_msg = NULL; 120.     reg->leave_msg = NULL; 121.     reg->expire_f = NO_CALLBACK; 122.     reg->enter_f = NO_CALLBACK; 123.     reg->can_enter_f = NO_CALLBACK; 124.     reg->leave_f = NO_CALLBACK; 125.     reg->can_leave_f = NO_CALLBACK; 126.     reg->inside_f = NO_CALLBACK; 127.     reg->player_inside = FALSE; 128.     reg->n_monst = 0; 129.     reg->max_monst = 0; 130.     reg->monsters = NULL; 131.     reg->arg = NULL; 132.     return reg; 133. }  134.   135.  /*  136.   * Add rectangle to region. 137.  */  138.  void 139. add_rect_to_reg(reg, rect) 140. NhRegion *reg; 141. NhRect *rect; 142. {  143.      NhRect *tmp_rect; 144.  145.      tmp_rect = (NhRect *) alloc(sizeof (NhRect) * (reg->nrects + 1)); 146.     if (reg->nrects > 0) { 147. 	(void) memcpy((genericptr_t) tmp_rect, (genericptr_t) reg->rects,  148.  		      (sizeof (NhRect) * reg->nrects)); 149. 	free((genericptr_t) reg->rects); 150.     }  151.      tmp_rect[reg->nrects] = *rect; 152.     reg->nrects++; 153.     reg->rects = tmp_rect; 154.     /* Update bounding box if needed */ 155.     if (reg->bounding_box.lx > rect->lx) 156. 	reg->bounding_box.lx = rect->lx; 157.     if (reg->bounding_box.ly > rect->ly) 158. 	reg->bounding_box.ly = rect->ly; 159.     if (reg->bounding_box.hx < rect->hx) 160. 	reg->bounding_box.hx = rect->hx; 161.     if (reg->bounding_box.hy < rect->hy) 162. 	reg->bounding_box.hy = rect->hy; 163. }  164.   165.  /*  166.   * Add a monster to the region 167.  */  168.  void 169. add_mon_to_reg(reg, mon) 170. NhRegion *reg; 171. struct monst *mon; 172. {  173.      int i;  174. unsigned *tmp_m; 175.  176.      if (reg->max_monst <= reg->n_monst) { 177. 	tmp_m = (unsigned *) 178. 		    alloc(sizeof (unsigned) * (reg->max_monst + MONST_INC)); 179. 	if (reg->max_monst > 0) { 180. 	    for (i = 0; i < reg->max_monst; i++) 181. 		tmp_m[i] = reg->monsters[i]; 182. 	    free((genericptr_t) reg->monsters); 183. 	}  184.  	reg->monsters = tmp_m; 185. 	reg->max_monst += MONST_INC; 186.     }  187.      reg->monsters[reg->n_monst++] = mon->m_id; 188. }  189.   190.  /*  191.   * Remove a monster from the region list (it left or died...) 192.  */  193.  void 194. remove_mon_from_reg(reg, mon) 195. NhRegion *reg; 196. struct monst *mon; 197. {  198.      register int i;  199. 200.     for (i = 0; i < reg->n_monst; i++) 201. 	if (reg->monsters[i] == mon->m_id) { 202. 	    reg->n_monst--; 203. 	    reg->monsters[i] = reg->monsters[reg->n_monst]; 204. 	    return; 205. 	}  206.  }  207.   208.  /*  209.   * Check if a monster is inside the region. 210.  * It's probably quicker to check with the region internal list 211.  * than to check for coordinates. 212.  */  213.  boolean 214. mon_in_region(reg, mon) 215. NhRegion *reg; 216. struct monst *mon; 217. {  218.      int i;  219. 220.     for (i = 0; i < reg->n_monst; i++) 221. 	if (reg->monsters[i] == mon->m_id) 222. 	    return TRUE; 223.     return FALSE; 224. }  225.   226.  #if 0 227. /* not yet used */ 228.  229.  /*  230.   * Clone (make a standalone copy) the region. 231.  */  232.  NhRegion * 233. clone_region(reg) 234. NhRegion *reg; 235. {  236.      NhRegion *ret_reg; 237.  238.      ret_reg = create_region(reg->rects, reg->nrects); 239.     ret_reg->ttl = reg->ttl; 240.     ret_reg->attach_2_u = reg->attach_2_u; 241.     ret_reg->attach_2_m = reg->attach_2_m; 242.  /* ret_reg->attach_2_o = reg->attach_2_o; */ 243.     ret_reg->expire_f = reg->expire_f; 244.     ret_reg->enter_f = reg->enter_f; 245.     ret_reg->can_enter_f = reg->can_enter_f; 246.     ret_reg->leave_f = reg->leave_f; 247.     ret_reg->can_leave_f = reg->can_leave_f; 248.     ret_reg->player_inside = reg->player_inside; 249.     ret_reg->n_monst = reg->n_monst; 250.     if (reg->n_monst > 0) { 251. 	ret_reg->monsters = (unsigned *) 252. 				alloc((sizeof (unsigned)) * reg->n_monst); 253. 	(void) memcpy((genericptr_t) ret_reg->monsters, (genericptr_t) reg->monsters,  254.  		      sizeof (unsigned) * reg->n_monst); 255.     } else 256. 	ret_reg->monsters = NULL; 257.     return ret_reg; 258. }  259.   260.  #endif	/*0*/ 261.  262.  /*  263.   * Free mem from region. 264.  */  265.  void 266. free_region(reg) 267. NhRegion *reg; 268. {  269.      if (reg) { 270. 	if (reg->rects) 271. 	    free((genericptr_t) reg->rects); 272. 	if (reg->monsters) 273. 	    free((genericptr_t) reg->monsters); 274. 	free((genericptr_t) reg); 275.     }  276.  }  277.   278.  /*  279.   * Add a region to the list. 280.  * This actually activates the region. 281.  */  282.  void 283. add_region(reg) 284. NhRegion *reg; 285. {  286.      NhRegion **tmp_reg; 287.     int i, j;  288. 289.     if (max_regions <= n_regions) { 290. 	tmp_reg = regions; 291. 	regions = (NhRegion **)alloc(sizeof (NhRegion *) * (max_regions + 10)); 292. 	if (max_regions > 0) { 293. 	    (void) memcpy((genericptr_t) regions, (genericptr_t) tmp_reg,  294.  			  max_regions * sizeof (NhRegion *)); 295. 	    free((genericptr_t) tmp_reg); 296. 	}  297.  	max_regions += 10; 298.     }  299.      regions[n_regions] = reg; 300.     n_regions++; 301.     /* Check for monsters inside the region */ 302.     for (i = reg->bounding_box.lx; i <= reg->bounding_box.hx; i++) 303. 	for (j = reg->bounding_box.ly; j <= reg->bounding_box.hy; j++) { 304. 	    /* Some regions can cross the level boundaries */ 305. 	    if (!isok(i,j)) 306. 		continue; 307. 	    if (MON_AT(i, j) && inside_region(reg, i, j)) 308. 		add_mon_to_reg(reg, level.monsters[i][j]); 309. 	    if (reg->visible && cansee(i, j)) 310. 		newsym(i, j); 311. 	}  312.      /* Check for player now... */ 313.      reg->player_inside = inside_region(reg, u.ux, u.uy); 314. }  315.   316.  /*  317.   * Remove a region from the list & free it. 318.  */  319.  void 320. remove_region(reg) 321. NhRegion *reg; 322. {  323.      register int i, x, y;  324. 325.     for (i = 0; i < n_regions; i++) 326. 	if (regions[i] == reg) 327. 	    break; 328.     if (i == n_regions) 329. 	return; 330.  331.      /* Update screen if necessary */ 332.     if (reg->visible) 333. 	for (x = reg->bounding_box.lx; x <= reg->bounding_box.hx; x++) 334. 	    for (y = reg->bounding_box.ly; y <= reg->bounding_box.hy; y++) 335. 		if (isok(x,y) && inside_region(reg, x, y) && cansee(x, y)) 336. 		    newsym(x, y); 337.  338.      free_region(reg); 339.     regions[i] = regions[n_regions - 1]; 340.     regions[n_regions - 1] = (NhRegion *) 0; 341.     n_regions--; 342. }  343.   344.  /*  345.   * Remove all regions and clear all related data (This must be down  346.   * when changing level, for instance). 347.  */  348.  void 349. clear_regions 350. {  351.      register int i;  352. 353.     for (i = 0; i < n_regions; i++) 354. 	free_region(regions[i]); 355.     n_regions = 0; 356.     if (max_regions > 0) 357. 	free((genericptr_t) regions); 358.     max_regions = 0; 359.     regions = NULL; 360. }  361.   362.  /*  363.   * This function is called every turn. 364.  * It makes the regions age, if necessary and calls the appropriate 365.  * callbacks when needed. 366.  */  367.  void 368. run_regions 369. {  370.      register int i, j, k;  371. int f_indx; 372.  373.      /* End of life ? */ 374.      /* Do it backward because the array will be modified */ 375.     for (i = n_regions - 1; i >= 0; i--) { 376. 	if (regions[i]->ttl == 0) { 377. 	    if ((f_indx = regions[i]->expire_f) == NO_CALLBACK ||  378.  		(*callbacks[f_indx])(regions[i], (genericptr_t) 0)) 379. 		remove_region(regions[i]); 380. 	}  381.      }  382.   383.      /* Process remaining regions */ 384.     for (i = 0; i < n_regions; i++) { 385. 	/* Make the region age */ 386. 	if (regions[i]->ttl > 0) 387. 	    regions[i]->ttl--; 388. 	/* Check if player is inside region */ 389. 	f_indx = regions[i]->inside_f; 390. 	if (f_indx != NO_CALLBACK && regions[i]->player_inside) 391. 	    (void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0); 392. 	/* Check if any monster is inside region */ 393. 	if (f_indx != NO_CALLBACK) { 394. 	    for (j = 0; j < regions[i]->n_monst; j++) { 395. 		struct monst *mtmp = find_mid(regions[i]->monsters[j], FM_FMON); 396.  397.  		if (!mtmp || mtmp->mhp <= 0 ||  398.  				(*callbacks[f_indx])(regions[i], mtmp)) { 399. 		    /* The monster died, remove it from list */ 400. 		    k = (regions[i]->n_monst -= 1); 401. 		    regions[i]->monsters[j] = regions[i]->monsters[k]; 402. 		    regions[i]->monsters[k] = 0; 403. 		    --j;    /* current slot has been reused; recheck it next */ 404. 		}  405.  	    }  406.  	}  407.      }  408.  }  409.   410.  /*  411.   * check whether player enters/leaves one or more regions. 412.  */  413.  boolean 414. in_out_region(x, y)  415. xchar 416.     x, y;  417. { 418.      int i, f_indx; 419.  420.      /* First check if we can do the move */ 421.     for (i = 0; i < n_regions; i++) { 422. 	if (inside_region(regions[i], x, y)  423.  	    && !regions[i]->player_inside && !regions[i]->attach_2_u) { 424. 	    if ((f_indx = regions[i]->can_enter_f) != NO_CALLBACK) 425. 		if (!(*callbacks[f_indx])(regions[i], (genericptr_t) 0)) 426. 		    return FALSE; 427. 	} else 428. 	    if (regions[i]->player_inside  429.  		&& !inside_region(regions[i], x, y)  430.  		&& !regions[i]->attach_2_u) { 431. 	    if ((f_indx = regions[i]->can_leave_f) != NO_CALLBACK) 432. 		if (!(*callbacks[f_indx])(regions[i], (genericptr_t) 0)) 433. 		    return FALSE; 434. 	}  435.      }  436.   437.      /* Callbacks for the regions we do leave */ 438.     for (i = 0; i < n_regions; i++) 439. 	if (regions[i]->player_inside &&  440.  		!regions[i]->attach_2_u && !inside_region(regions[i], x, y)) { 441. 	    regions[i]->player_inside = FALSE; 442. 	    if (regions[i]->leave_msg != NULL) 443. 		pline(regions[i]->leave_msg); 444. 	    if ((f_indx = regions[i]->leave_f) != NO_CALLBACK) 445. 		(void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0); 446. 	}  447.   448.      /* Callbacks for the regions we do enter */ 449.     for (i = 0; i < n_regions; i++) 450. 	if (!regions[i]->player_inside &&  451.  		!regions[i]->attach_2_u && inside_region(regions[i], x, y)) { 452. 	    regions[i]->player_inside = TRUE; 453. 	    if (regions[i]->enter_msg != NULL) 454. 		pline(regions[i]->enter_msg); 455. 	    if ((f_indx = regions[i]->enter_f) != NO_CALLBACK) 456. 		(void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0); 457. 	}  458.      return TRUE; 459. }  460.   461.  /*  462.   * check wether a monster enters/leaves one or more region. 463. */  464.  boolean 465. m_in_out_region(mon, x, y)  466. struct monst *mon; 467. xchar x, y;  468. { 469.      int i, f_indx; 470.  471.      /* First check if we can do the move */ 472.     for (i = 0; i < n_regions; i++) { 473. 	if (inside_region(regions[i], x, y) &&  474.  		!mon_in_region(regions[i], mon) &&  475.  		regions[i]->attach_2_m != mon->m_id) { 476. 	    if ((f_indx = regions[i]->can_enter_f) != NO_CALLBACK) 477. 		if (!(*callbacks[f_indx])(regions[i], mon)) 478. 		    return FALSE; 479. 	} else if (mon_in_region(regions[i], mon) &&  480.  		!inside_region(regions[i], x, y) &&  481.  		regions[i]->attach_2_m != mon->m_id) { 482. 	    if ((f_indx = regions[i]->can_leave_f) != NO_CALLBACK) 483. 		if (!(*callbacks[f_indx])(regions[i], mon)) 484. 		    return FALSE; 485. 	}  486.      }  487.   488.      /* Callbacks for the regions we do leave */ 489.     for (i = 0; i < n_regions; i++) 490. 	if (mon_in_region(regions[i], mon) &&  491.  		regions[i]->attach_2_m != mon->m_id &&  492.  		!inside_region(regions[i], x, y)) { 493. 	    remove_mon_from_reg(regions[i], mon); 494. 	    if ((f_indx = regions[i]->leave_f) != NO_CALLBACK) 495. 		(void) (*callbacks[f_indx])(regions[i], mon); 496. 	}  497.   498.      /* Callbacks for the regions we do enter */ 499.     for (i = 0; i < n_regions; i++) 500. 	if (!regions[i]->player_inside &&  501.  		!regions[i]->attach_2_u && inside_region(regions[i], x, y)) { 502. 	    add_mon_to_reg(regions[i], mon); 503. 	    if ((f_indx = regions[i]->enter_f) != NO_CALLBACK) 504. 		(void) (*callbacks[f_indx])(regions[i], mon); 505. 	}  506.      return TRUE; 507. }  508.   509.  /*  510.   * Checks player's regions after a teleport for instance. 511.  */  512.  void 513. update_player_regions 514. {  515.      register int i;  516. 517.     for (i = 0; i < n_regions; i++) 518. 	if (!regions[i]->attach_2_u) 519. 	    regions[i]->player_inside = inside_region(regions[i], u.ux, u.uy); 520. 	else 521. 	    regions[i]->player_inside = FALSE; 522. }  523.   524.  /*  525.   * Ditto for a specified monster. 526.  */  527.  void 528. update_monster_region(mon) 529. struct monst *mon; 530. {  531.      register int i;  532. 533.     for (i = 0; i < n_regions; i++) { 534. 	if (inside_region(regions[i], mon->mx, mon->my)) { 535. 	    if (!mon_in_region(regions[i], mon)) 536. 		add_mon_to_reg(regions[i], mon); 537. 	} else { 538. 	    if (mon_in_region(regions[i], mon)) 539. 		remove_mon_from_reg(regions[i], mon); 540. 	}  541.      }  542.  }  543.   544.  #if 0 545. /* not yet used */ 546.  547.  /*  548.   * Change monster pointer in regions 549.  * This happens, for instance, when a monster grows and 550.  * need a new structure (internally that is). 551.  */  552.  void 553. replace_mon_regions(monold, monnew) 554. struct monst *monold, *monnew; 555. {  556.      register int i;  557. 558.     for (i = 0; i < n_regions; i++) 559. 	if (mon_in_region(regions[i], monold)) { 560. 	    remove_mon_from_reg(regions[i], monold); 561. 	    add_mon_to_reg(regions[i], monnew); 562. 	}  563.  }  564.   565.  /*  566.   * Remove monster from all regions it was in (ie monster just died) 567.  */  568.  void 569. remove_mon_from_regions(mon) 570. struct monst *mon; 571. {  572.      register int i;  573. 574.     for (i = 0; i < n_regions; i++) 575. 	if (mon_in_region(regions[i], mon)) 576. 	    remove_mon_from_reg(regions[i], mon); 577. }  578.   579.  #endif	/*0*/ 580.  581.  /*  582.   * Check if a spot is under a visible region (eg: gas cloud). 583.  * Returns NULL if not, otherwise returns region. 584.  */  585.  NhRegion * 586. visible_region_at(x, y)  587. xchar x, y; 588. { 589.      register int i;  590. 591.     for (i = 0; i < n_regions; i++) 592. 	if (inside_region(regions[i], x, y) && regions[i]->visible &&  593.  		regions[i]->ttl != 0) 594. 	    return regions[i]; 595.     return (NhRegion *) 0; 596. }  597.   598.  void 599. show_region(reg, x, y)  600. NhRegion *reg; 601. xchar x, y;  602. { 603.      show_glyph(x, y, reg->glyph); 604. }  605.   606.  /**  607.   * save_regions : 608.  */  609.  void 610. save_regions(fd, mode) 611. int fd; 612. int mode; 613. {  614.      int i, j;  615. unsigned n; 616. 617.     if (!perform_bwrite(mode)) goto skip_lots; 618.  619.      bwrite(fd, (genericptr_t) &moves, sizeof (moves));	/* timestamp */ 620.     bwrite(fd, (genericptr_t) &n_regions, sizeof (n_regions)); 621.     for (i = 0; i < n_regions; i++) { 622. 	bwrite(fd, (genericptr_t) &regions[i]->bounding_box, sizeof (NhRect)); 623. 	bwrite(fd, (genericptr_t) &regions[i]->nrects, sizeof (short)); 624. 	for (j = 0; j < regions[i]->nrects; j++) 625. 	    bwrite(fd, (genericptr_t) &regions[i]->rects[j], sizeof (NhRect)); 626. 	bwrite(fd, (genericptr_t) &regions[i]->attach_2_u, sizeof (boolean)); 627. 	n = 0; 628. 	bwrite(fd, (genericptr_t) &regions[i]->attach_2_m, sizeof (unsigned)); 629. 	n = regions[i]->enter_msg != NULL ? strlen(regions[i]->enter_msg) : 0; 630. 	bwrite(fd, (genericptr_t) &n, sizeof n); 631. 	if (n > 0) 632. 	    bwrite(fd, (genericptr_t) regions[i]->enter_msg, n); 633. 	n = regions[i]->leave_msg != NULL ? strlen(regions[i]->leave_msg) : 0; 634. 	bwrite(fd, (genericptr_t) &n, sizeof n); 635. 	if (n > 0) 636. 	    bwrite(fd, (genericptr_t) regions[i]->leave_msg, n); 637. 	bwrite(fd, (genericptr_t) &regions[i]->ttl, sizeof (short)); 638. 	bwrite(fd, (genericptr_t) &regions[i]->expire_f, sizeof (short)); 639. 	bwrite(fd, (genericptr_t) &regions[i]->can_enter_f, sizeof (short)); 640. 	bwrite(fd, (genericptr_t) &regions[i]->enter_f, sizeof (short)); 641. 	bwrite(fd, (genericptr_t) &regions[i]->can_leave_f, sizeof (short)); 642. 	bwrite(fd, (genericptr_t) &regions[i]->leave_f, sizeof (short)); 643. 	bwrite(fd, (genericptr_t) &regions[i]->inside_f, sizeof (short)); 644. 	bwrite(fd, (genericptr_t) &regions[i]->player_inside, sizeof (boolean)); 645. 	bwrite(fd, (genericptr_t) &regions[i]->n_monst, sizeof (short)); 646. 	for (j = 0; j < regions[i]->n_monst; j++) 647. 	    bwrite(fd, (genericptr_t) &regions[i]->monsters[j],  648.  	     sizeof (unsigned)); 649. 	bwrite(fd, (genericptr_t) &regions[i]->visible, sizeof (boolean)); 650. 	bwrite(fd, (genericptr_t) &regions[i]->glyph, sizeof (int)); 651. 	bwrite(fd, (genericptr_t) &regions[i]->arg, sizeof (genericptr_t)); 652.     }  653.   654.  skip_lots: 655.     if (release_data(mode)) 656. 	clear_regions; 657. }  658.   659.  void 660. rest_regions(fd) 661. int fd; 662. {  663.      int i, j;  664. unsigned n; 665. long tmstamp; 666.     char *msg_buf; 667.  668.      clear_regions;		/* Just for security */ 669.     mread(fd, (genericptr_t) &tmstamp, sizeof (tmstamp)); 670.     tmstamp = (moves - tmstamp); 671.     mread(fd, (genericptr_t) &n_regions, sizeof (n_regions)); 672.     max_regions = n_regions; 673.     if (n_regions > 0) 674. 	regions = (NhRegion **) alloc(sizeof (NhRegion *) * n_regions); 675.     for (i = 0; i < n_regions; i++) { 676. 	regions[i] = (NhRegion *) alloc(sizeof (NhRegion)); 677. 	mread(fd, (genericptr_t) &regions[i]->bounding_box, sizeof (NhRect)); 678. 	mread(fd, (genericptr_t) &regions[i]->nrects, sizeof (short)); 679.  680.  	if (regions[i]->nrects > 0) 681. 	    regions[i]->rects = (NhRect *) 682. 				  alloc(sizeof (NhRect) * regions[i]->nrects); 683. 	for (j = 0; j < regions[i]->nrects; j++) 684. 	    mread(fd, (genericptr_t) &regions[i]->rects[j], sizeof (NhRect)); 685. 	mread(fd, (genericptr_t) &regions[i]->attach_2_u, sizeof (boolean)); 686. 	mread(fd, (genericptr_t) &regions[i]->attach_2_m, sizeof (unsigned)); 687.  688.  	mread(fd, (genericptr_t) &n, sizeof n); 689. 	if (n > 0) { 690. 	    msg_buf = (char *) alloc(n + 1); 691. 	    mread(fd, (genericptr_t) msg_buf, n); 692. 	    msg_buf[n] = '\0'; 693. 	    regions[i]->enter_msg = (const char *) msg_buf; 694. 	} else 695. 	    regions[i]->enter_msg = NULL; 696.  697.  	mread(fd, (genericptr_t) &n, sizeof n); 698. 	if (n > 0) { 699. 	    msg_buf = (char *) alloc(n + 1); 700. 	    mread(fd, (genericptr_t) msg_buf, n); 701. 	    msg_buf[n] = '\0'; 702. 	    regions[i]->leave_msg = (const char *) msg_buf; 703. 	} else 704. 	    regions[i]->leave_msg = NULL; 705.  706.  	mread(fd, (genericptr_t) &regions[i]->ttl, sizeof (short)); 707. 	/* check for expired region */ 708. 	if (regions[i]->ttl >= 0) 709. 	    regions[i]->ttl = 710. 		(regions[i]->ttl > tmstamp) ? regions[i]->ttl - tmstamp : 0; 711. 	mread(fd, (genericptr_t) &regions[i]->expire_f, sizeof (short)); 712. 	mread(fd, (genericptr_t) &regions[i]->can_enter_f, sizeof (short)); 713. 	mread(fd, (genericptr_t) &regions[i]->enter_f, sizeof (short)); 714. 	mread(fd, (genericptr_t) &regions[i]->can_leave_f, sizeof (short)); 715. 	mread(fd, (genericptr_t) &regions[i]->leave_f, sizeof (short)); 716. 	mread(fd, (genericptr_t) &regions[i]->inside_f, sizeof (short)); 717. 	mread(fd, (genericptr_t) &regions[i]->player_inside, sizeof (boolean)); 718. 	mread(fd, (genericptr_t) &regions[i]->n_monst, sizeof (short)); 719. 	if (regions[i]->n_monst > 0) 720. 	    regions[i]->monsters = 721. 		(unsigned *) alloc(sizeof (unsigned) * regions[i]->n_monst); 722. 	else 723. 	    regions[i]->monsters = NULL; 724. 	regions[i]->max_monst = regions[i]->n_monst; 725. 	for (j = 0; j < regions[i]->n_monst; j++) 726. 	    mread(fd, (genericptr_t) &regions[i]->monsters[j],  727.  		  sizeof (unsigned)); 728. 	mread(fd, (genericptr_t) &regions[i]->visible, sizeof (boolean)); 729. 	mread(fd, (genericptr_t) &regions[i]->glyph, sizeof (int)); 730. 	mread(fd, (genericptr_t) &regions[i]->arg, sizeof (genericptr_t)); 731.     }  732.      /* remove expired regions, do not trigger the expire_f callback (yet!) */ 733.     for (i = n_regions - 1; i >= 0; i--) 734. 	if (regions[i]->ttl == 0) 735. 	    remove_region(regions[i]); 736. }  737.   738.  #if 0 739. /* not yet used */ 740.  741.  /*--*  742.   *								*  743.   *			Create Region with just a message	* 744.  *								*  745.   *--*/  746.   747.  NhRegion * 748. create_msg_region(x, y, w, h, msg_enter, msg_leave) 749. xchar x, y;  750. xchar w, h; 751. const char *msg_enter; 752. const char *msg_leave; 753. {  754.      NhRect tmprect; 755.     NhRegion *reg = create_region((NhRect *) 0, 0); 756.  757.      reg->enter_msg = msg_enter; 758.     reg->leave_msg = msg_leave; 759.     tmprect.lx = x;  760. tmprect.ly = y; 761. tmprect.hx = x + w; 762. tmprect.hy = y + h; 763. add_rect_to_reg(reg, &tmprect); 764.     reg->ttl = -1; 765.     return reg; 766. }  767.   768.   769.  /*--*  770.   *								*  771.   *			Force Field Related Code		* 772.  *			(unused yet)				* 773.  *--*/  774.   775.  boolean 776. enter_force_field(p1, p2) 777. genericptr_t p1; 778. genericptr_t p2; 779. {  780.      struct monst *mtmp; 781.  782.      if (p2 == NULL) {		/* That means the player */ 783. 	if (!Blind) 784. 		You("bump into %s. Ouch!",  785.  		    Hallucination ? "an invisible tree" :  786.  			"some kind of invisible wall"); 787. 	else 788. 	    pline("Ouch!"); 789.     } else { 790. 	mtmp = (struct monst *) p2; 791. 	if (canseemon(mtmp)) 792. 	    pline("%s bumps into %s!", Monnam(mtmp), something); 793.     }  794.      return FALSE; 795. }  796.   797.  NhRegion * 798. create_force_field(x, y, radius, ttl) 799. xchar x, y;  800. int radius, ttl; 801. {  802.      int i;  803. NhRegion *ff; 804.     int nrect; 805.     NhRect tmprect; 806.  807.      ff = create_region((NhRect *) 0, 0); 808.     nrect = radius; 809.     tmprect.lx = x;  810. tmprect.hx = x; 811. tmprect.ly = y - (radius - 1); 812.     tmprect.hy = y + (radius - 1); 813.     for (i = 0; i < nrect; i++) { 814. 	add_rect_to_reg(ff, &tmprect); 815. 	tmprect.lx--; 816. 	tmprect.hx++; 817. 	tmprect.ly++; 818. 	tmprect.hy--; 819.     }  820.      ff->ttl = ttl; 821.  /* ff->can_enter_f = enter_force_field; */ 822.  /* ff->can_leave_f = enter_force_field; */ 823.     add_region(ff); 824.     return ff; 825. }  826.   827.  #endif	/*0*/ 828.  829.  /*--*  830.   *								*  831.   *			Gas cloud related code			* 832.  *								*  833.   *--*/  834.   835.  /*  836.   * Here is an example of an expire function that may prolong 837.  * region life after some mods...  838. */ 839.  boolean 840. expire_gas_cloud(p1, p2) 841. genericptr_t p1; 842. genericptr_t p2; 843. {  844.      NhRegion *reg; 845.     int damage; 846.  847.      reg = (NhRegion *) p1; 848.     damage = (int) reg->arg; 849.  850.      /* If it was a thick cloud, it dissipates a little first */ 851.     if (damage >= 5) { 852. 	damage /= 2;		/* It dissipates, let's do less damage */ 853. 	reg->arg = (genericptr_t) damage; 854. 	reg->ttl = 2;		/* Here's the trick : reset ttl */ 855. 	return FALSE;		/* THEN return FALSE, means "still there" */ 856.     }  857.      return TRUE;		/* OK, it's gone, you can free it! */ 858.  }  859.   860.  boolean 861. inside_gas_cloud(p1, p2) 862. genericptr_t p1; 863. genericptr_t p2; 864. {  865.      NhRegion *reg; 866.     struct monst *mtmp; 867.     int dam; 868.  869.      reg = (NhRegion *) p1; 870.     dam = (int) reg->arg; 871.     if (p2 == NULL) {		/* This means *YOU* Bozo! */ 872.  	if (nonliving(youmonst.data) || Breathless) 873. 	    return FALSE; 874. 	if (!Blind) 875. 	    make_blinded(1L, FALSE); 876. 	if (!Poison_resistance) { 877. 	    pline("%s is burning your %s!", Something, makeplural(body_part(LUNG))); 878. 	    You("cough and spit blood!"); 879. 	    losehp(rnd(dam) + 5, "gas cloud", KILLED_BY_AN); 880. 	    return FALSE; 881. 	} else { 882. 	    You("cough!"); 883. 	    return FALSE; 884. 	}  885.      } else {			/* A monster is inside the cloud */ 886. 	mtmp = (struct monst *) p2; 887.  888.  	/* Non living and non breathing monsters are not concerned */ 889. 	if (!nonliving(mtmp->data) && !breathless(mtmp->data)) { 890. 	    if (cansee(mtmp->mx, mtmp->my)) 891. 		pline("%s coughs!", Monnam(mtmp)); 892. 	    setmangry(mtmp); 893. 	    if (haseyes(mtmp->data) && mtmp->mcansee) { 894. 		mtmp->mblinded = 1; 895. 		mtmp->mcansee = 0; 896. 	    }  897.  	    if (resists_poison(mtmp)) 898. 		return FALSE; 899. 	    mtmp->mhp -= rnd(dam) + 5; 900. 	    if (mtmp->mhp <= 0) { 901. 		killed(mtmp); 902. 		if (mtmp->mhp <= 0) {	/* not lifesaved */ 903. 		    return TRUE; 904. 		}  905.  	    }  906.  	}  907.      }  908.      return FALSE;		/* Monster is still alive */ 909. }  910.   911.  NhRegion * 912. create_gas_cloud(x, y, radius, damage) 913. xchar x, y;  914. int radius; 915. int damage; 916. {  917.      NhRegion *cloud; 918.     int i, nrect; 919.     NhRect tmprect; 920.  921.      cloud = create_region((NhRect *) 0, 0); 922.     nrect = radius; 923.     tmprect.lx = x;  924. tmprect.hx = x; 925. tmprect.ly = y - (radius - 1); 926.     tmprect.hy = y + (radius - 1); 927.     for (i = 0; i < nrect; i++) { 928. 	add_rect_to_reg(cloud, &tmprect); 929. 	tmprect.lx--; 930. 	tmprect.hx++; 931. 	tmprect.ly++; 932. 	tmprect.hy--; 933.     }  934.      cloud->ttl = rn1(3,4); 935.     cloud->inside_f = INSIDE_GAS_CLOUD; 936.     cloud->expire_f = EXPIRE_GAS_CLOUD; 937.     cloud->arg = (genericptr_t) damage; 938.     cloud->visible = TRUE; 939.     cloud->glyph = cmap_to_glyph(S_cloud); 940.     add_region(cloud); 941.     return cloud; 942. }  943.   944.  /*region.c*/