Source:NetHack 3.3.0/region.c
Revision as of 11:36, 4 March 2008 by Kernigh bot (talk | contribs) (NetHack 3.3.0/region.c moved to Source:NetHack 3.3.0/region.c: Robot: moved page)
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
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. /* 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) ®ions[i]->bounding_box, sizeof (NhRect)); 625. bwrite(fd, (genericptr_t) ®ions[i]->nrects, sizeof (short)); 626. for (j = 0; j < regions[i]->nrects; j++) 627. bwrite(fd, (genericptr_t) ®ions[i]->rects[j], sizeof (NhRect)); 628. bwrite(fd, (genericptr_t) ®ions[i]->attach_2_u, sizeof (boolean)); 629. n = 0; 630. bwrite(fd, (genericptr_t) ®ions[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) ®ions[i]->ttl, sizeof (short)); 640. bwrite(fd, (genericptr_t) ®ions[i]->expire_f, sizeof (short)); 641. bwrite(fd, (genericptr_t) ®ions[i]->can_enter_f, sizeof (short)); 642. bwrite(fd, (genericptr_t) ®ions[i]->enter_f, sizeof (short)); 643. bwrite(fd, (genericptr_t) ®ions[i]->can_leave_f, sizeof (short)); 644. bwrite(fd, (genericptr_t) ®ions[i]->leave_f, sizeof (short)); 645. bwrite(fd, (genericptr_t) ®ions[i]->inside_f, sizeof (short)); 646. bwrite(fd, (genericptr_t) ®ions[i]->player_inside, sizeof (boolean)); 647. bwrite(fd, (genericptr_t) ®ions[i]->n_monst, sizeof (short)); 648. for (j = 0; j < regions[i]->n_monst; j++) 649. bwrite(fd, (genericptr_t) ®ions[i]->monsters[j], 650. sizeof (unsigned)); 651. bwrite(fd, (genericptr_t) ®ions[i]->visible, sizeof (boolean)); 652. bwrite(fd, (genericptr_t) ®ions[i]->glyph, sizeof (int)); 653. bwrite(fd, (genericptr_t) ®ions[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) ®ions[i]->bounding_box, sizeof (NhRect)); 676. mread(fd, (genericptr_t) ®ions[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) ®ions[i]->rects[j], sizeof (NhRect)); 683. mread(fd, (genericptr_t) ®ions[i]->attach_2_u, sizeof (boolean)); 684. mread(fd, (genericptr_t) ®ions[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) ®ions[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) ®ions[i]->expire_f, sizeof (short)); 710. mread(fd, (genericptr_t) ®ions[i]->can_enter_f, sizeof (short)); 711. mread(fd, (genericptr_t) ®ions[i]->enter_f, sizeof (short)); 712. mread(fd, (genericptr_t) ®ions[i]->can_leave_f, sizeof (short)); 713. mread(fd, (genericptr_t) ®ions[i]->leave_f, sizeof (short)); 714. mread(fd, (genericptr_t) ®ions[i]->inside_f, sizeof (short)); 715. mread(fd, (genericptr_t) ®ions[i]->player_inside, sizeof (boolean)); 716. mread(fd, (genericptr_t) ®ions[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) ®ions[i]->monsters[j], 725. sizeof (unsigned)); 726. mread(fd, (genericptr_t) ®ions[i]->visible, sizeof (boolean)); 727. mread(fd, (genericptr_t) ®ions[i]->glyph, sizeof (int)); 728. mread(fd, (genericptr_t) ®ions[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*/