Source:NetHack 3.3.0/region.c

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